1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "tools/edit_gui_common.h"
30 
31 
32 #include "qe3.h"
33 #include "Radiant.h"
34 #include "XYWnd.h"
35 #include "DialogInfo.h"
36 #include "splines.h"
37 #include "../../renderer/tr_local.h"
38 #include "../../renderer/model_local.h"	// for idRenderModelLiquid
39 
40 #ifdef _DEBUG
41 	#define new DEBUG_NEW
42 	#undef THIS_FILE
43 static char		THIS_FILE[] = __FILE__;
44 #endif
45 
46 const char		*g_pDimStrings[] = { "x:%.f", "y:%.f", "z:%.f" };
47 const char		*g_pOrgStrings[] = { "(x:%.f  y:%.f)", "(x:%.f  z:%.f)", "(y:%.f  z:%.f)" };
48 CString			g_strDim;
49 CString			g_strStatus;
50 
51 bool			g_bCrossHairs = false;
52 bool			g_bScaleMode;
53 int				g_nScaleHow;
54 bool			g_bRotateMode;
55 bool			g_bClipMode;
56 bool			g_bRogueClipMode;
57 bool			g_bSwitch;
58 CClipPoint		g_Clip1;
59 CClipPoint		g_Clip2;
60 CClipPoint		g_Clip3;
61 CClipPoint		*g_pMovingClip;
62 brush_t			g_brFrontSplits;
63 brush_t			g_brBackSplits;
64 
65 brush_t			g_brClipboard;
66 brush_t			g_brUndo;
67 entity_t		g_enClipboard;
68 
69 idVec3			g_vRotateOrigin;
70 idVec3			g_vRotation;
71 
72 bool			g_bPathMode;
73 CClipPoint		g_PathPoints[256];
74 CClipPoint		*g_pMovingPath;
75 int				g_nPathCount;
76 int				g_nPathLimit;
77 
78 bool			g_bSmartGo;
79 
80 bool			g_bPointMode;
81 CClipPoint		g_PointPoints[512];
82 CClipPoint		*g_pMovingPoint;
83 int				g_nPointCount;
84 int				g_nPointLimit;
85 
86 const int		XY_LEFT = 0x01;
87 const int		XY_RIGHT = 0x02;
88 const int		XY_UP = 0x04;
89 const int		XY_DOWN = 0x08;
90 
91 PFNPathCallback *g_pPathFunc = NULL;
92 void	Select_Ungroup();
93 
94 /*
95  =======================================================================================================================
96  =======================================================================================================================
97  */
AcquirePath(int nCount,PFNPathCallback * pFunc)98 void AcquirePath(int nCount, PFNPathCallback *pFunc) {
99 	g_nPathCount = 0;
100 	g_nPathLimit = nCount;
101 	g_pPathFunc = pFunc;
102 	g_bPathMode = true;
103 }
104 
105 CPtrArray	g_ptrMenus;
106 
107 CMemFile	g_Clipboard(4096);
108 CMemFile	g_PatchClipboard(4096);
109 
110 extern int	pressx;
111 extern int	pressy;
112 
113 /*
114  =======================================================================================================================
115  =======================================================================================================================
116  */
fDiff(float f1,float f2)117 float fDiff(float f1, float f2) {
118 	if (f1 > f2) {
119 		return f1 - f2;
120 	}
121 	else {
122 		return f2 - f1;
123 	}
124 }
125 
126 #define MAX_DRAG_POINTS 128
127 
128 CPtrArray			dragPoints;
129 static CDragPoint	*activeDrag = NULL;
130 static bool			activeDragging = false;
131 
132 /*
133  =======================================================================================================================
134  =======================================================================================================================
135  */
PointWithin(idVec3 p,int nView)136 bool CDragPoint::PointWithin(idVec3 p, int nView) {
137 	if (nView == -1) {
138 		if (fDiff(p[0], vec[0]) <= 3 && fDiff(p[1], vec[1]) <= 3 && fDiff(p[2], vec[2]) <= 3) {
139 			return true;
140 		}
141 	}
142 	else {
143 		int nDim1 = (nView == YZ) ? 1 : 0;
144 		int nDim2 = (nView == XY) ? 1 : 2;
145 		if (fDiff(p[nDim1], vec[nDim1]) <= 3 && fDiff(p[nDim2], vec[nDim2]) <= 3) {
146 			return true;
147 		}
148 	}
149 
150 	return false;
151 }
152 
153 /*
154  =======================================================================================================================
155  =======================================================================================================================
156  */
PointRay(const idVec3 & org,const idVec3 & dir,float * dist)157 CDragPoint *PointRay(const idVec3 &org, const idVec3 &dir, float *dist) {
158 	int			i, besti;
159 	float		d, bestd;
160 	idVec3		temp;
161 	CDragPoint	*drag = NULL;
162 	CDragPoint	*priority = NULL;
163 
164 	// find the point closest to the ray
165 	float scale = g_pParentWnd->ActiveXY()->Scale();
166 	besti = -1;
167 	bestd = 12 / scale / 2;
168 
169 	int count = dragPoints.GetSize();
170 	for (i = 0; i < count; i++) {
171 		drag = reinterpret_cast < CDragPoint * > (dragPoints[i]);
172 		temp = drag->vec - org;
173 		d = temp * dir;
174 		temp = org + d * dir;
175 		temp = drag->vec - temp;
176 		d = temp.Length();
177 		if ( d < bestd ) {
178 			bestd = d;
179 			besti = i;
180 			if (priority == NULL) {
181 				priority = reinterpret_cast < CDragPoint * > (dragPoints[besti]);
182 				if (!priority->priority) {
183 					priority = NULL;
184 				}
185 			}
186 		}
187 	}
188 
189 	if (besti == -1) {
190 		return NULL;
191 	}
192 
193 	drag = reinterpret_cast < CDragPoint * > (dragPoints[besti]);
194 	if (priority && !drag->priority) {
195 		drag = priority;
196 	}
197 
198 	return drag;
199 }
200 
201 /*
202  =======================================================================================================================
203  =======================================================================================================================
204  */
ClearSelectablePoints(brush_t * b)205 void ClearSelectablePoints(brush_t *b) {
206 	if (b == NULL) {
207 		dragPoints.RemoveAll();
208 	}
209 	else {
210 		CPtrArray	ptr;
211 		ptr.Copy(dragPoints);
212 		dragPoints.RemoveAll();
213 
214 		int count = ptr.GetSize();
215 		for (int i = 0; i < count; i++) {
216 			if (b == reinterpret_cast < CDragPoint * > ( ptr.GetAt(i))->pBrush ) {
217 				continue;
218 			}
219 			else {
220 				dragPoints.Add(ptr.GetAt(i));
221 			}
222 		}
223 	}
224 }
225 
226 /*
227  =======================================================================================================================
228  =======================================================================================================================
229  */
AddSelectablePoint(brush_t * b,idVec3 v,int type,bool priority)230 void AddSelectablePoint(brush_t *b, idVec3 v, int type, bool priority) {
231 	dragPoints.Add(new CDragPoint(b, v, type, priority));
232 }
233 
234 /*
235  =======================================================================================================================
236  =======================================================================================================================
237  */
UpdateSelectablePoint(brush_t * b,idVec3 v,int type)238 void UpdateSelectablePoint(brush_t *b, idVec3 v, int type) {
239 	int count = dragPoints.GetSize();
240 	for (int i = 0; i < count; i++) {
241 		CDragPoint	*drag = reinterpret_cast < CDragPoint * > (dragPoints.GetAt(i));
242 		if (b == drag->pBrush && type == drag->nType) {
243 			VectorCopy(v, drag->vec);
244 			return;
245 		}
246 	}
247 }
248 
249 /*
250  =======================================================================================================================
251  =======================================================================================================================
252  */
VectorToAngles(idVec3 vec,idVec3 angles)253 void VectorToAngles(idVec3 vec, idVec3 angles) {
254 	float	forward;
255 	float	yaw, pitch;
256 
257 	if ((vec[0] == 0) && (vec[1] == 0)) {
258 		yaw = 0;
259 		if (vec[2] > 0) {
260 			pitch = 90;
261 		}
262 		else {
263 			pitch = 270;
264 		}
265 	}
266 	else {
267 		yaw = RAD2DEG( atan2(vec[1], vec[0]) );
268 		if (yaw < 0) {
269 			yaw += 360;
270 		}
271 
272 		forward = (float)idMath::Sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
273 		pitch = RAD2DEG( atan2(vec[2], forward) );
274 		if (pitch < 0) {
275 			pitch += 360;
276 		}
277 	}
278 
279 	angles[0] = pitch;
280 	angles[1] = yaw;
281 	angles[2] = 0;
282 }
283 
284 /*
285  =======================================================================================================================
286 	RotateLight target is relative to the light origin up and right are relative to the target up and right are
287 	perpendicular and are on a plane through the target with the target vector as normal delta is the movement of the
288 	target relative to the light
289  =======================================================================================================================
290 */
VectorSnapGrid(idVec3 & v)291 void VectorSnapGrid(idVec3 &v) {
292 	v.x = floor(v.x / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
293 	v.y = floor(v.y / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
294 	v.z = floor(v.z / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
295 }
296 
297 /*
298  =======================================================================================================================
299  =======================================================================================================================
300 */
RotateLight(idVec3 & target,idVec3 & up,idVec3 & right,const idVec3 & delta)301 static void RotateLight(idVec3 &target, idVec3 &up, idVec3 &right, const idVec3 &delta) {
302 	idVec3	newtarget, cross, dst;
303 	idVec3	normal;
304 	double	angle, dist, d, len;
305 	idMat3	rot;
306 
307 	// calculate new target
308 	newtarget = target + delta;
309 
310 	// get the up and right vector relative to the light origin
311 	up += target;
312 	right += target;
313 
314 	len = target.Length() * newtarget.Length();
315 
316 	if (len > 0.1) {
317 		// calculate the rotation angle between the vectors
318 		double	dp = target * newtarget;
319 		double	dv = dp / len;
320 
321 		angle = RAD2DEG( idMath::ACos( dv ) );
322 
323 		// get a vector orthogonal to the rotation plane
324 		cross = target.Cross( newtarget );
325 		cross.Normalize();
326 
327 		if (cross[0] || cross[1] || cross[2]) {
328 			// build the rotation matrix
329 			rot = idRotation( vec3_origin, cross, angle ).ToMat3();
330 
331 			rot.ProjectVector(target, dst);
332 			target = dst;
333 			rot.ProjectVector( up, dst );
334 			up = dst;
335 			rot.ProjectVector( right, dst);
336 			right = dst;
337 		}
338 	}
339 
340 	//
341 	// project the up and right vectors onto a plane that goes through the target and
342 	// has normal vector target.Normalize()
343 	//
344 	normal = target;
345 	normal.Normalize();
346 	dist = normal * target;
347 
348 	d = (normal * up) - dist;
349 	up -= d * normal;
350 
351 	d = (normal * right) - dist;
352 	right -= d * normal;
353 
354 	//
355 	// FIXME: maybe calculate the right vector with a cross product between the target
356 	// and up vector, just to make sure the up and right vectors are perpendicular
357 	// get the up and right vectors relative to the target
358 	//
359 	up -= target;
360 	right -= target;
361 
362 	// move the target in the (target - light_origin) direction
363 	target = newtarget;
364 	VectorSnapGrid(target);
365 	VectorSnapGrid(up);
366 	VectorSnapGrid(right);
367 }
368 
369 /*
370  =======================================================================================================================
371  =======================================================================================================================
372 */
373 extern idVec3 Brush_TransformedPoint(brush_t *b, const idVec3 &in);
374 extern idMat3 Brush_RotationMatrix(brush_t *b);
UpdateActiveDragPoint(const idVec3 & move)375 bool UpdateActiveDragPoint(const idVec3 &move) {
376 	if (activeDrag) {
377 		idMat3 mat = Brush_RotationMatrix(activeDrag->pBrush);
378 		idMat3 invmat = mat.Transpose();
379 		idVec3	target, up, right, start, end;
380 		CString str;
381 		if (activeDrag->nType == LIGHT_TARGET) {
382 			GetVectorForKey(activeDrag->pBrush->owner, "light_target", target);
383 			GetVectorForKey(activeDrag->pBrush->owner, "light_up", up);
384 			GetVectorForKey(activeDrag->pBrush->owner, "light_right", right);
385 			target *= mat;
386 			up *= mat;
387 			right *= mat;
388 			RotateLight(target, up, right, move);
389 			target *= invmat;
390 			up *= invmat;
391 			right *= invmat;
392 			SetKeyVec3(activeDrag->pBrush->owner, "light_target", target);
393 			SetKeyVec3(activeDrag->pBrush->owner, "light_up", up);
394 			SetKeyVec3(activeDrag->pBrush->owner, "light_right", right);
395 			target += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
396 			UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush, target), LIGHT_TARGET);
397 			up += target;
398 			UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,up), LIGHT_UP);
399 			right += target;
400 			UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,right), LIGHT_RIGHT);
401 		}
402 		else if (activeDrag->nType == LIGHT_UP) {
403 			GetVectorForKey(activeDrag->pBrush->owner, "light_up", up);
404 			up *= mat;
405 			up += move;
406 			up *= invmat;
407 			SetKeyVec3(activeDrag->pBrush->owner, "light_up", up);
408 			GetVectorForKey(activeDrag->pBrush->owner, "light_target", target);
409 			target += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
410 			up += target;
411 			UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,up), LIGHT_UP);
412 		}
413 		else if (activeDrag->nType == LIGHT_RIGHT) {
414 			GetVectorForKey(activeDrag->pBrush->owner, "light_right", right);
415 			right *= mat;
416 			right += move;
417 			right *= invmat;
418 			SetKeyVec3(activeDrag->pBrush->owner, "light_right", right);
419 			GetVectorForKey(activeDrag->pBrush->owner, "light_target", target);
420 			target += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
421 			right += target;
422 			UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,right), LIGHT_RIGHT);
423 		}
424 		else if (activeDrag->nType == LIGHT_START) {
425 			GetVectorForKey(activeDrag->pBrush->owner, "light_start", start);
426 			start *= mat;
427 			start += move;
428 			start *= invmat;
429 			SetKeyVec3(activeDrag->pBrush->owner, "light_start", start);
430 			start += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
431 			UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,start), LIGHT_START);
432 		}
433 		else if (activeDrag->nType == LIGHT_END) {
434 			GetVectorForKey(activeDrag->pBrush->owner, "light_end", end);
435 			end *= mat;
436 			end += move;
437 			end *= invmat;
438 			SetKeyVec3(activeDrag->pBrush->owner, "light_end", end);
439 			end += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
440 			UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,end), LIGHT_END);
441 		}
442 		else if (activeDrag->nType == LIGHT_CENTER) {
443 			GetVectorForKey(activeDrag->pBrush->owner, "light_center", end);
444 			end *= mat;
445 			end += move;
446 			end *= invmat;
447 			SetKeyVec3(activeDrag->pBrush->owner, "light_center", end);
448 			end += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
449 			UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush, end), LIGHT_CENTER);
450 		}
451 
452 		// FIXME: just build the frustrum values
453 		Brush_Build(activeDrag->pBrush);
454 		return true;
455 	}
456 
457 	return false;
458 }
459 
460 /*
461  =======================================================================================================================
462  =======================================================================================================================
463 */
SetDragPointCursor(idVec3 p,int nView)464 bool SetDragPointCursor(idVec3 p, int nView) {
465 	activeDrag = NULL;
466 
467 	int numDragPoints = dragPoints.GetSize();
468 	for (int i = 0; i < numDragPoints; i++) {
469 		if (reinterpret_cast < CDragPoint * > (dragPoints[i])->PointWithin(p, nView)) {
470 			activeDrag = reinterpret_cast < CDragPoint * > (dragPoints[i]);
471 			return true;
472 		}
473 	}
474 
475 	return false;
476 }
477 
478 /*
479  =======================================================================================================================
480  =======================================================================================================================
481  */
SetActiveDrag(CDragPoint * p)482 void SetActiveDrag(CDragPoint *p) {
483 	activeDrag = p;
484 }
485 
486 /*
487  =======================================================================================================================
488  =======================================================================================================================
489  */
ClearActiveDrag()490 void ClearActiveDrag() {
491 	activeDrag = NULL;
492 }
493 
494 // CXYWnd
495 IMPLEMENT_DYNCREATE(CXYWnd, CWnd);
496 
497 /*
498  =======================================================================================================================
499  =======================================================================================================================
500  */
CXYWnd()501 CXYWnd::CXYWnd() {
502 	g_brClipboard.next = &g_brClipboard;
503 	g_brUndo.next = &g_brUndo;
504 	g_nScaleHow = 0;
505 	g_bRotateMode = false;
506 	g_bClipMode = false;
507 	g_bRogueClipMode = false;
508 	g_bSwitch = true;
509 	g_pMovingClip = NULL;
510 	g_pMovingPath = NULL;
511 	g_brFrontSplits.next = &g_brFrontSplits;
512 	g_brBackSplits.next = &g_brBackSplits;
513 	m_bActive = false;
514 
515 	m_bRButtonDown = false;
516 	m_nUpdateBits = W_XY;
517 	g_bPathMode = false;
518 	g_nPathCount = 0;
519 	g_nPathLimit = 0;
520 	m_nTimerID = -1;
521 	m_nButtonstate = 0;
522 	XY_Init();
523 }
524 
525 /*
526  =======================================================================================================================
527  =======================================================================================================================
528  */
~CXYWnd()529 CXYWnd::~CXYWnd() {
530 	int nSize = g_ptrMenus.GetSize();
531 	while (nSize > 0) {
532 		CMenu	*pMenu = reinterpret_cast < CMenu * > (g_ptrMenus.GetAt(nSize - 1));
533 		ASSERT(pMenu);
534 		pMenu->DestroyMenu();
535 		delete pMenu;
536 		nSize--;
537 	}
538 
539 	g_ptrMenus.RemoveAll();
540 	m_mnuDrop.DestroyMenu();
541 }
542 
543 BEGIN_MESSAGE_MAP(CXYWnd, CWnd)
544 //{{AFX_MSG_MAP(CXYWnd)
545 	ON_WM_CREATE()
546 	ON_WM_LBUTTONDOWN()
547 	ON_WM_MBUTTONDOWN()
548 	ON_WM_RBUTTONDOWN()
549 	ON_WM_LBUTTONUP()
550 	ON_WM_MBUTTONUP()
551 	ON_WM_RBUTTONUP()
552 	ON_WM_MOUSEMOVE()
553 	ON_WM_PAINT()
554 	ON_WM_KEYDOWN()
555 	ON_WM_SIZE()
556 	ON_WM_DESTROY()
557 	ON_COMMAND(ID_SELECT_MOUSEROTATE, OnSelectMouserotate)
558 	ON_WM_TIMER()
559 	ON_WM_KEYUP()
560 	ON_WM_NCCALCSIZE()
561 	ON_WM_KILLFOCUS()
562 	ON_WM_SETFOCUS()
563 	ON_WM_CLOSE()
564 	ON_WM_ERASEBKGND()
565 	ON_WM_MOUSEWHEEL()
566 	ON_COMMAND(ID_DROP_NEWMODEL, OnDropNewmodel)
567 	//}}AFX_MSG_MAP
568 	ON_COMMAND_RANGE(ID_ENTITY_START, ID_ENTITY_END, OnEntityCreate)
569 END_MESSAGE_MAP()
570 // CXYWnd message handlers
571 LONG WINAPI XYWndProc(HWND, UINT, WPARAM, LPARAM);
572 
573 /*
574  =======================================================================================================================
575  =======================================================================================================================
576  */
PreCreateWindow(CREATESTRUCT & cs)577 BOOL CXYWnd::PreCreateWindow(CREATESTRUCT &cs) {
578 	WNDCLASS	wc;
579 	HINSTANCE	hInstance = AfxGetInstanceHandle();
580 	if (::GetClassInfo(hInstance, XY_WINDOW_CLASS, &wc) == FALSE) {
581 		// Register a new class
582 		memset(&wc, 0, sizeof(wc));
583 		wc.style = CS_NOCLOSE;
584 		wc.lpszClassName = XY_WINDOW_CLASS;
585 		wc.hCursor = NULL;	// LoadCursor (NULL,IDC_ARROW);
586 		wc.lpfnWndProc = ::DefWindowProc;
587 		if (AfxRegisterClass(&wc) == FALSE) {
588 			Error("CCamWnd RegisterClass: failed");
589 		}
590 	}
591 
592 	cs.lpszClass = XY_WINDOW_CLASS;
593 	cs.lpszName = "VIEW";
594 	if (cs.style != QE3_CHILDSTYLE) {
595 		cs.style = QE3_SPLITTER_STYLE;
596 	}
597 
598 	return CWnd::PreCreateWindow(cs);
599 }
600 
601 HDC				s_hdcXY;
602 HGLRC			s_hglrcXY;
603 
604 static unsigned s_stipple[32] = {
605 	0xaaaaaaaa,
606 	0x55555555,
607 	0xaaaaaaaa,
608 	0x55555555,
609 	0xaaaaaaaa,
610 	0x55555555,
611 	0xaaaaaaaa,
612 	0x55555555,
613 	0xaaaaaaaa,
614 	0x55555555,
615 	0xaaaaaaaa,
616 	0x55555555,
617 	0xaaaaaaaa,
618 	0x55555555,
619 	0xaaaaaaaa,
620 	0x55555555,
621 	0xaaaaaaaa,
622 	0x55555555,
623 	0xaaaaaaaa,
624 	0x55555555,
625 	0xaaaaaaaa,
626 	0x55555555,
627 	0xaaaaaaaa,
628 	0x55555555,
629 	0xaaaaaaaa,
630 	0x55555555,
631 	0xaaaaaaaa,
632 	0x55555555,
633 	0xaaaaaaaa,
634 	0x55555555,
635 	0xaaaaaaaa,
636 	0x55555555,
637 };
638 
639 /*
640  =======================================================================================================================
641 	WXY_WndProc
642  =======================================================================================================================
643  */
XYWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)644 LONG WINAPI XYWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
645 	switch (uMsg)
646 	{
647 		case WM_DESTROY:
648 			return 0;
649 
650 		case WM_NCCALCSIZE: // don't let windows copy pixels
651 			DefWindowProc(hWnd, uMsg, wParam, lParam);
652 			return WVR_REDRAW;
653 
654 		case WM_KILLFOCUS:
655 		case WM_SETFOCUS:
656 			SendMessage(hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0);
657 			return 0;
658 
659 		case WM_CLOSE:
660 			DestroyWindow(hWnd);
661 			return 0;
662 	}
663 
664 	return DefWindowProc(hWnd, uMsg, wParam, lParam);
665 }
666 
667 /*
668  =======================================================================================================================
669  =======================================================================================================================
670  */
WXY_InitPixelFormat(PIXELFORMATDESCRIPTOR * pPFD)671 static void WXY_InitPixelFormat(PIXELFORMATDESCRIPTOR *pPFD) {
672 	memset(pPFD, 0, sizeof(*pPFD));
673 
674 	pPFD->nSize = sizeof(PIXELFORMATDESCRIPTOR);
675 	pPFD->nVersion = 1;
676 	pPFD->dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
677 	pPFD->iPixelType = PFD_TYPE_RGBA;
678 	pPFD->cColorBits = 24;
679 	pPFD->cDepthBits = 32;
680 	pPFD->iLayerType = PFD_MAIN_PLANE;
681 }
682 
683 /*
684  =======================================================================================================================
685  =======================================================================================================================
686  */
WXY_Print(void)687 void WXY_Print(void) {
688 	DOCINFO		di;
689 
690 	PRINTDLG	pd;
691 
692 	/* initialize the PRINTDLG struct and execute it */
693 	memset(&pd, 0, sizeof(pd));
694 	pd.lStructSize = sizeof(pd);
695 	pd.hwndOwner = g_pParentWnd->GetXYWnd()->GetSafeHwnd();
696 	pd.Flags = PD_RETURNDC;
697 	pd.hInstance = 0;
698 	if (!PrintDlg(&pd) || !pd.hDC) {
699 		g_pParentWnd->MessageBox("Could not PrintDlg()", "QE4 Print Error", MB_OK | MB_ICONERROR);
700 		return;
701 	}
702 
703 	/* StartDoc */
704 	memset(&di, 0, sizeof(di));
705 	di.cbSize = sizeof(di);
706 	di.lpszDocName = "QE4";
707 	if (StartDoc(pd.hDC, &di) <= 0) {
708 		g_pParentWnd->MessageBox("Could not StartDoc()", "QE4 Print Error", MB_OK | MB_ICONERROR);
709 		return;
710 	}
711 
712 	/* StartPage */
713 	if (StartPage(pd.hDC) <= 0) {
714 		g_pParentWnd->MessageBox("Could not StartPage()", "QE4 Print Error", MB_OK | MB_ICONERROR);
715 		return;
716 	} { /* read pixels from the XY window */
717 		int		bmwidth = 320, bmheight = 320;
718 		int		pwidth, pheight;
719 
720 		RECT	r;
721 
722 		GetWindowRect(g_pParentWnd->GetXYWnd()->GetSafeHwnd(), &r);
723 
724 		bmwidth = r.right - r.left;
725 		bmheight = r.bottom - r.top;
726 
727 		pwidth = GetDeviceCaps(pd.hDC, PHYSICALWIDTH) - GetDeviceCaps(pd.hDC, PHYSICALOFFSETX);
728 		pheight = GetDeviceCaps(pd.hDC, PHYSICALHEIGHT) - GetDeviceCaps(pd.hDC, PHYSICALOFFSETY);
729 
730 		StretchBlt(pd.hDC, 0, 0, pwidth, pheight, s_hdcXY, 0, 0, bmwidth, bmheight, SRCCOPY);
731 	}
732 
733 	/* EndPage and EndDoc */
734 	if (EndPage(pd.hDC) <= 0) {
735 		g_pParentWnd->MessageBox("QE4 Print Error", "Could not EndPage()", MB_OK | MB_ICONERROR);
736 		return;
737 	}
738 
739 	if (EndDoc(pd.hDC) <= 0) {
740 		g_pParentWnd->MessageBox("QE4 Print Error", "Could not EndDoc()", MB_OK | MB_ICONERROR);
741 		return;
742 	}
743 }
744 
745 /*
746  =======================================================================================================================
747  =======================================================================================================================
748  */
OnCreate(LPCREATESTRUCT lpCreateStruct)749 int CXYWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
750 	if (CWnd::OnCreate(lpCreateStruct) == -1) {
751 		return -1;
752 	}
753 
754 	s_hdcXY = ::GetDC(GetSafeHwnd());
755 	QEW_SetupPixelFormat(s_hdcXY, false);
756 
757 	qglPolygonStipple((unsigned char *)s_stipple);
758 	qglLineStipple(3, 0xaaaa);
759 	return 0;
760 }
761 
762 /*
763  =======================================================================================================================
764  =======================================================================================================================
765  */
ptSum(idVec3 pt)766 float ptSum(idVec3 pt) {
767 	return pt[0] + pt[1] + pt[2];
768 }
769 
770 /*
771  =======================================================================================================================
772  =======================================================================================================================
773  */
DropClipPoint(UINT nFlags,CPoint point)774 void CXYWnd::DropClipPoint(UINT nFlags, CPoint point) {
775 	CRect	rctZ;
776 	GetClientRect(rctZ);
777 	if (g_pMovingClip) {
778 		SetCapture();
779 		SnapToPoint(point.x, rctZ.Height() - 1 - point.y, *g_pMovingClip);
780 	}
781 	else {
782 		idVec3	*pPt = NULL;
783 		if (g_Clip1.Set() == false) {
784 			pPt = g_Clip1;
785 			g_Clip1.Set(true);
786 			g_Clip1.m_ptScreen = point;
787 		}
788 		else if (g_Clip2.Set() == false) {
789 			pPt = g_Clip2;
790 			g_Clip2.Set(true);
791 			g_Clip2.m_ptScreen = point;
792 		}
793 		else if (g_Clip3.Set() == false) {
794 			pPt = g_Clip3;
795 			g_Clip3.Set(true);
796 			g_Clip3.m_ptScreen = point;
797 		}
798 		else {
799 			RetainClipMode(true);
800 			pPt = g_Clip1;
801 			g_Clip1.Set(true);
802 			g_Clip1.m_ptScreen = point;
803 		}
804 
805 		SnapToPoint(point.x, rctZ.Height() - 1 - point.y, *pPt);
806 
807 		// Put the off-viewaxis coordinate at the top or bottom of selected brushes
808 		if ( GetAsyncKeyState(VK_CONTROL) & 0x8000 ) {
809 			if ( selected_brushes.next != &selected_brushes ) {
810 				idVec3	smins, smaxs;
811 				Select_GetBounds( smins, smaxs );
812 
813 				if ( m_nViewType == XY ) {
814 					if ( GetAsyncKeyState(VK_SHIFT) & 0x8000 ) {
815 						pPt->z = smaxs.z;
816 					} else {
817 						pPt->z = smins.z;
818 					}
819 				} else if ( m_nViewType == YZ ) {
820 					if ( GetAsyncKeyState(VK_SHIFT) & 0x8000 ) {
821 						pPt->x = smaxs.x;
822 					} else {
823 						pPt->x = smins.x;
824 					}
825 				} else {
826 					if ( GetAsyncKeyState(VK_SHIFT) & 0x8000 ) {
827 						pPt->y = smaxs.y;
828 					} else {
829 						pPt->y = smins.y;
830 					}
831 				}
832 			}
833 		}
834 	}
835 
836 	Sys_UpdateWindows(XY | W_CAMERA_IFON);
837 }
838 
839 /*
840  =======================================================================================================================
841  =======================================================================================================================
842  */
DropPathPoint(UINT nFlags,CPoint point)843 void CXYWnd::DropPathPoint(UINT nFlags, CPoint point) {
844 	CRect	rctZ;
845 	GetClientRect(rctZ);
846 	if (g_pMovingPath) {
847 		SetCapture();
848 		SnapToPoint(point.x, rctZ.Height() - 1 - point.y, *g_pMovingPath);
849 	}
850 	else {
851 		g_PathPoints[g_nPathCount].Set(true);
852 		g_PathPoints[g_nPathCount].m_ptScreen = point;
853 		SnapToPoint(point.x, rctZ.Height() - 1 - point.y, g_PathPoints[g_nPathCount]);
854 		g_nPathCount++;
855 		if (g_nPathCount == g_nPathLimit) {
856 			if (g_pPathFunc) {
857 				g_pPathFunc(true, g_nPathCount);
858 			}
859 
860 			g_nPathCount = 0;
861 			g_bPathMode = false;
862 			g_pPathFunc = NULL;
863 		}
864 	}
865 
866 	Sys_UpdateWindows(XY | W_CAMERA_IFON);
867 }
868 
869 /*
870  =======================================================================================================================
871  =======================================================================================================================
872  */
AddPointPoint(UINT nFlags,idVec3 * pVec)873 void CXYWnd::AddPointPoint(UINT nFlags, idVec3 *pVec) {
874 	g_PointPoints[g_nPointCount].Set(true);
875 
876 	// g_PointPoints[g_nPointCount].m_ptScreen = point;
877 	g_PointPoints[g_nPointCount].m_ptClip = *pVec;
878 	g_PointPoints[g_nPointCount].SetPointPtr(pVec);
879 	g_nPointCount++;
880 	Sys_UpdateWindows(XY | W_CAMERA_IFON);
881 }
882 
883 /*
884  =======================================================================================================================
885  =======================================================================================================================
886  */
OnLButtonDown(UINT nFlags,CPoint point)887 void CXYWnd::OnLButtonDown(UINT nFlags, CPoint point) {
888 	g_pParentWnd->SetActiveXY(this);
889 	UndoCopy();
890 
891 	if (g_pParentWnd->GetNurbMode()) {
892 		int i, num = g_pParentWnd->GetNurb()->GetNumValues();
893 		idList<idVec2> temp;
894 			for (i = 0; i < num; i++) {
895 			temp.Append(g_pParentWnd->GetNurb()->GetValue(i));
896 		}
897 		CRect	rctZ;
898 		GetClientRect(rctZ);
899 		idVec3 v3;
900 		SnapToPoint(point.x, rctZ.Height() - 1 - point.y, v3);
901 		temp.Append(idVec2(v3.x, v3.y));
902 		num++;
903 		g_pParentWnd->GetNurb()->Clear();
904 		for (i = 0; i < num; i++) {
905 			g_pParentWnd->GetNurb()->AddValue((1000 * i)/num, temp[i]);
906 		}
907 	}
908 	if (ClipMode() && !RogueClipMode()) {
909 		DropClipPoint(nFlags, point);
910 	}
911 	else if (PathMode()) {
912 		DropPathPoint(nFlags, point);
913 	}
914 	else {
915 		OriginalButtonDown(nFlags, point);
916 	}
917 }
918 
919 /*
920  =======================================================================================================================
921  =======================================================================================================================
922  */
OnMButtonDown(UINT nFlags,CPoint point)923 void CXYWnd::OnMButtonDown(UINT nFlags, CPoint point) {
924 	OriginalButtonDown(nFlags, point);
925 }
926 
927 /*
928  =======================================================================================================================
929  =======================================================================================================================
930  */
Betwixt(float f1,float f2)931 float Betwixt(float f1, float f2) {
932 	if (f1 > f2) {
933 		return f2 + ((f1 - f2) / 2);
934 	}
935 	else {
936 		return f1 + ((f2 - f1) / 2);
937 	}
938 }
939 
940 /*
941  =======================================================================================================================
942  =======================================================================================================================
943  */
ProduceSplits(brush_t ** pFront,brush_t ** pBack)944 void CXYWnd::ProduceSplits(brush_t **pFront, brush_t **pBack) {
945 	*pFront = NULL;
946 	*pBack = NULL;
947 	if (ClipMode()) {
948 		if (g_Clip1.Set() && g_Clip2.Set()) {
949 			face_t	face;
950 			VectorCopy(g_Clip1.m_ptClip, face.planepts[0]);
951 			VectorCopy(g_Clip2.m_ptClip, face.planepts[1]);
952 			VectorCopy(g_Clip3.m_ptClip, face.planepts[2]);
953 			if (selected_brushes.next && (selected_brushes.next->next == &selected_brushes)) {
954 				if (g_Clip3.Set() == false) {
955 					if (m_nViewType == XY) {
956 						face.planepts[0][2] = selected_brushes.next->mins[2];
957 						face.planepts[1][2] = selected_brushes.next->mins[2];
958 						face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
959 						face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
960 						face.planepts[2][2] = selected_brushes.next->maxs[2];
961 					}
962 					else if (m_nViewType == YZ) {
963 						face.planepts[0][0] = selected_brushes.next->mins[0];
964 						face.planepts[1][0] = selected_brushes.next->mins[0];
965 						face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
966 						face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
967 						face.planepts[2][0] = selected_brushes.next->maxs[0];
968 					}
969 					else {
970 						face.planepts[0][1] = selected_brushes.next->mins[1];
971 						face.planepts[1][1] = selected_brushes.next->mins[1];
972 						face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
973 						face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
974 						face.planepts[2][1] = selected_brushes.next->maxs[1];
975 					}
976 				}
977 
978 				Brush_SplitBrushByFace(selected_brushes.next, &face, pFront, pBack);
979 			}
980 		}
981 	}
982 }
983 
984 /*
985  =======================================================================================================================
986  =======================================================================================================================
987  */
CleanList(brush_t * pList)988 void CleanList(brush_t *pList) {
989 	brush_t *pBrush = pList->next;
990 	while (pBrush != NULL && pBrush != pList) {
991 		brush_t *pNext = pBrush->next;
992 		Brush_Free(pBrush);
993 		pBrush = pNext;
994 	}
995 }
996 
997 /*
998  =======================================================================================================================
999  =======================================================================================================================
1000  */
ProduceSplitLists()1001 void CXYWnd::ProduceSplitLists() {
1002 	if (AnyPatchesSelected()) {
1003 		Sys_Status("Deslecting patches for clip operation.\n");
1004 
1005 		brush_t *next;
1006 		for (brush_t * pb = selected_brushes.next; pb != &selected_brushes; pb = next) {
1007 			next = pb->next;
1008 			if (pb->pPatch) {
1009 				Brush_RemoveFromList(pb);
1010 				Brush_AddToList(pb, &active_brushes);
1011 				UpdatePatchInspector();
1012 			}
1013 		}
1014 	}
1015 
1016 	CleanList(&g_brFrontSplits);
1017 	CleanList(&g_brBackSplits);
1018 	g_brFrontSplits.next = &g_brFrontSplits;
1019 	g_brBackSplits.next = &g_brBackSplits;
1020 
1021 	brush_t *pBrush;
1022 	for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) {
1023 		brush_t *pFront = NULL;
1024 		brush_t *pBack = NULL;
1025 		if (ClipMode()) {
1026 			if (g_Clip1.Set() && g_Clip2.Set()) {
1027 				face_t	face;
1028 				VectorCopy(g_Clip1.m_ptClip, face.planepts[0]);
1029 				VectorCopy(g_Clip2.m_ptClip, face.planepts[1]);
1030 				VectorCopy(g_Clip3.m_ptClip, face.planepts[2]);
1031 				if (g_Clip3.Set() == false) {
1032 					if (g_pParentWnd->ActiveXY()->GetViewType() == XY) {
1033 						face.planepts[0][2] = pBrush->mins[2];
1034 						face.planepts[1][2] = pBrush->mins[2];
1035 						face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
1036 						face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
1037 						face.planepts[2][2] = pBrush->maxs[2];
1038 					}
1039 					else if (g_pParentWnd->ActiveXY()->GetViewType() == YZ) {
1040 						face.planepts[0][0] = pBrush->mins[0];
1041 						face.planepts[1][0] = pBrush->mins[0];
1042 						face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
1043 						face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
1044 						face.planepts[2][0] = pBrush->maxs[0];
1045 					}
1046 					else {
1047 						face.planepts[0][1] = pBrush->mins[1];
1048 						face.planepts[1][1] = pBrush->mins[1];
1049 						face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
1050 						face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
1051 						face.planepts[2][1] = pBrush->maxs[1];
1052 					}
1053 				}
1054 
1055 				Brush_SplitBrushByFace(pBrush, &face, &pFront, &pBack);
1056 				if (pBack) {
1057 					Brush_AddToList(pBack, &g_brBackSplits);
1058 				}
1059 
1060 				if (pFront) {
1061 					Brush_AddToList(pFront, &g_brFrontSplits);
1062 				}
1063 			}
1064 		}
1065 	}
1066 }
1067 
1068 /*
1069  =======================================================================================================================
1070  =======================================================================================================================
1071  */
Brush_CopyList(brush_t * pFrom,brush_t * pTo)1072 void Brush_CopyList(brush_t *pFrom, brush_t *pTo) {
1073 	brush_t *pBrush = pFrom->next;
1074 	while (pBrush != NULL && pBrush != pFrom) {
1075 		brush_t *pNext = pBrush->next;
1076 		Brush_RemoveFromList(pBrush);
1077 		Brush_AddToList(pBrush, pTo);
1078 		pBrush = pNext;
1079 	}
1080 }
1081 
1082 /*
1083  =======================================================================================================================
1084  =======================================================================================================================
1085  */
OnRButtonDown(UINT nFlags,CPoint point)1086 void CXYWnd::OnRButtonDown(UINT nFlags, CPoint point) {
1087 	g_pParentWnd->SetActiveXY(this);
1088 	m_ptDown = point;
1089 	m_bRButtonDown = true;
1090 
1091 	if (g_PrefsDlg.m_nMouseButtons == 3) {	// 3 button mouse
1092 		if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) {
1093 			if (ClipMode()) {				// already there?
1094 				DropClipPoint(nFlags, point);
1095 			}
1096 			else {
1097 				SetClipMode(true);
1098 				g_bRogueClipMode = true;
1099 				DropClipPoint(nFlags, point);
1100 			}
1101 
1102 			return;
1103 		}
1104 	}
1105 
1106 	OriginalButtonDown(nFlags, point);
1107 }
1108 
1109 /*
1110  =======================================================================================================================
1111  =======================================================================================================================
1112  */
OnLButtonUp(UINT nFlags,CPoint point)1113 void CXYWnd::OnLButtonUp(UINT nFlags, CPoint point) {
1114 
1115 	if (ClipMode()) {
1116 		if (g_pMovingClip) {
1117 			ReleaseCapture();
1118 			g_pMovingClip = NULL;
1119 		}
1120 	}
1121 
1122 	OriginalButtonUp(nFlags, point);
1123 }
1124 
1125 /*
1126  =======================================================================================================================
1127  =======================================================================================================================
1128  */
OnMButtonUp(UINT nFlags,CPoint point)1129 void CXYWnd::OnMButtonUp(UINT nFlags, CPoint point) {
1130 	OriginalButtonUp(nFlags, point);
1131 }
1132 
1133 /*
1134  =======================================================================================================================
1135  =======================================================================================================================
1136  */
OnRButtonUp(UINT nFlags,CPoint point)1137 void CXYWnd::OnRButtonUp(UINT nFlags, CPoint point) {
1138 	m_bRButtonDown = false;
1139 	if (point == m_ptDown) {	// mouse didn't move
1140 		bool	bGo = true;
1141 		if ((GetAsyncKeyState(VK_MENU) & 0x8000)) {
1142 			bGo = false;
1143 		}
1144 
1145 		if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) {
1146 			bGo = false;
1147 		}
1148 
1149 		if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) {
1150 			bGo = false;
1151 		}
1152 
1153 		if (bGo) {
1154 			HandleDrop();
1155 		}
1156 	}
1157 
1158 	OriginalButtonUp(nFlags, point);
1159 }
1160 
1161 /*
1162  =======================================================================================================================
1163  =======================================================================================================================
1164  */
OriginalButtonDown(UINT nFlags,CPoint point)1165 void CXYWnd::OriginalButtonDown(UINT nFlags, CPoint point) {
1166 	CRect	rctZ;
1167 	GetClientRect(rctZ);
1168 	SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1169 	if (g_pParentWnd->GetTopWindow() != this) {
1170 		BringWindowToTop();
1171 	}
1172 
1173 	SetFocus();
1174 	SetCapture();
1175 	XY_MouseDown(point.x, rctZ.Height() - 1 - point.y, nFlags);
1176 	m_nScrollFlags = nFlags;
1177 }
1178 
1179 /*
1180  =======================================================================================================================
1181  =======================================================================================================================
1182  */
OriginalButtonUp(UINT nFlags,CPoint point)1183 void CXYWnd::OriginalButtonUp(UINT nFlags, CPoint point) {
1184 	CRect	rctZ;
1185 	GetClientRect(rctZ);
1186 	XY_MouseUp(point.x, rctZ.Height() - 1 - point.y, nFlags);
1187 	if (!(nFlags & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON))) {
1188 		ReleaseCapture();
1189 	}
1190 }
1191 
1192 idVec3	tdp;
1193 
1194 /*
1195  =======================================================================================================================
1196  =======================================================================================================================
1197  */
OnMouseMove(UINT nFlags,CPoint point)1198 void CXYWnd::OnMouseMove(UINT nFlags, CPoint point) {
1199 
1200 	m_ptDown.x = 0;
1201 	m_ptDown.y = 0;
1202 
1203 	if
1204 	(
1205 		g_PrefsDlg.m_bChaseMouse == TRUE &&
1206 		(point.x < 0 || point.y < 0 || point.x > m_nWidth || point.y > m_nHeight) &&
1207 		GetCapture() == this
1208 	) {
1209 		float	fAdjustment = (g_qeglobals.d_gridsize / 8 * 64) / m_fScale;
1210 
1211 		// m_ptDrag = point;
1212 		m_ptDragAdj.x = 0;
1213 		m_ptDragAdj.y = 0;
1214 		if (point.x < 0) {
1215 			m_ptDragAdj.x = -fAdjustment;
1216 		}
1217 		else if (point.x > m_nWidth) {
1218 			m_ptDragAdj.x = fAdjustment;
1219 		}
1220 
1221 		if (point.y < 0) {
1222 			m_ptDragAdj.y = -fAdjustment;
1223 		}
1224 		else if (point.y > m_nHeight) {
1225 			m_ptDragAdj.y = fAdjustment;
1226 		}
1227 
1228 		if (m_nTimerID == -1) {
1229 			m_nTimerID = SetTimer(100, 50, NULL);
1230 			m_ptDrag = point;
1231 			m_ptDragTotal = 0;
1232 		}
1233 
1234 		return;
1235 	}
1236 
1237 	// else if (m_nTimerID != -1)
1238 	if (m_nTimerID != -1) {
1239 		KillTimer(m_nTimerID);
1240 		pressx -= m_ptDragTotal.x;
1241 		pressy += m_ptDragTotal.y;
1242 		m_nTimerID = -1;
1243 
1244 		// return;
1245 	}
1246 
1247 	bool	bCrossHair = false;
1248 	if (!m_bRButtonDown) {
1249 		tdp[0] = tdp[1] = tdp[2] = 0.0;
1250 		SnapToPoint(point.x, m_nHeight - 1 - point.y, tdp);
1251 
1252 		g_strStatus.Format("x:: %.1f  y:: %.1f  z:: %.1f", tdp[0], tdp[1], tdp[2]);
1253 		g_pParentWnd->SetStatusText(1, g_strStatus);
1254 
1255 		//
1256 		// i need to generalize the point code.. having 3 flavors pretty much sucks.. once
1257 		// the new curve stuff looks like it is going to stick i will rationalize this
1258 		// down to a single interface..
1259 		//
1260 		if (PointMode()) {
1261 			if (g_pMovingPoint && GetCapture() == this) {
1262 				bCrossHair = true;
1263 				SnapToPoint(point.x, m_nHeight - 1 - point.y, g_pMovingPoint->m_ptClip);
1264 				g_pMovingPoint->UpdatePointPtr();
1265 				Sys_UpdateWindows(XY | W_CAMERA_IFON);
1266 			}
1267 			else {
1268 				g_pMovingPoint = NULL;
1269 
1270 				int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1271 				int nDim2 = (m_nViewType == XY) ? 1 : 2;
1272 				for (int n = 0; n < g_nPointCount; n++) {
1273 					if
1274 					(
1275 						fDiff(g_PointPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1276 						fDiff(g_PointPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3
1277 					) {
1278 						bCrossHair = true;
1279 						g_pMovingPoint = &g_PointPoints[n];
1280 					}
1281 				}
1282 			}
1283 		}
1284 		else if (ClipMode()) {
1285 			if (g_pMovingClip && GetCapture() == this) {
1286 				bCrossHair = true;
1287 				SnapToPoint(point.x, m_nHeight - 1 - point.y, g_pMovingClip->m_ptClip);
1288 				Sys_UpdateWindows(XY | W_CAMERA_IFON);
1289 			}
1290 			else {
1291 				g_pMovingClip = NULL;
1292 
1293 				int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1294 				int nDim2 = (m_nViewType == XY) ? 1 : 2;
1295 				if (g_Clip1.Set()) {
1296 					if
1297 					(
1298 						fDiff(g_Clip1.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1299 						fDiff(g_Clip1.m_ptClip[nDim2], tdp[nDim2]) < 3
1300 					) {
1301 						bCrossHair = true;
1302 						g_pMovingClip = &g_Clip1;
1303 					}
1304 				}
1305 
1306 				if (g_Clip2.Set()) {
1307 					if
1308 					(
1309 						fDiff(g_Clip2.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1310 						fDiff(g_Clip2.m_ptClip[nDim2], tdp[nDim2]) < 3
1311 					) {
1312 						bCrossHair = true;
1313 						g_pMovingClip = &g_Clip2;
1314 					}
1315 				}
1316 
1317 				if (g_Clip3.Set()) {
1318 					if
1319 					(
1320 						fDiff(g_Clip3.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1321 						fDiff(g_Clip3.m_ptClip[nDim2], tdp[nDim2]) < 3
1322 					) {
1323 						bCrossHair = true;
1324 						g_pMovingClip = &g_Clip3;
1325 					}
1326 				}
1327 			}
1328 
1329 			if (bCrossHair == false) {
1330 				XY_MouseMoved(point.x, m_nHeight - 1 - point.y, nFlags);
1331 			}
1332 		}
1333 		else if (PathMode()) {
1334 			if (g_pMovingPath && GetCapture() == this) {
1335 				bCrossHair = true;
1336 				SnapToPoint(point.x, m_nHeight - 1 - point.y, g_pMovingPath->m_ptClip);
1337 				Sys_UpdateWindows(XY | W_CAMERA_IFON);
1338 			}
1339 			else {
1340 				g_pMovingPath = NULL;
1341 
1342 				int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1343 				int nDim2 = (m_nViewType == XY) ? 1 : 2;
1344 				for (int n = 0; n < g_nPathCount; n++) {
1345 					if
1346 					(
1347 						fDiff(g_PathPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1348 						fDiff(g_PathPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3
1349 					) {
1350 						bCrossHair = true;
1351 						g_pMovingPath = &g_PathPoints[n];
1352 					}
1353 				}
1354 			}
1355 		}
1356 		else {
1357 			bCrossHair = XY_MouseMoved(point.x, m_nHeight - 1 - point.y, nFlags);
1358 		}
1359 	}
1360 	else {
1361 		bCrossHair = XY_MouseMoved(point.x, m_nHeight - 1 - point.y, nFlags);
1362 	}
1363 
1364 	if (bCrossHair) {
1365 		SetCursor(::LoadCursor(NULL, IDC_CROSS));
1366 	}
1367 	else {
1368 		SetCursor(::LoadCursor(NULL, IDC_ARROW));
1369 	}
1370 
1371 	/// If precision crosshair is active, force redraw of the 2d view on mouse move
1372 	if( m_precisionCrosshairMode != PRECISION_CROSSHAIR_NONE )
1373 	{
1374 		/// Force 2d view redraw (so that the precision cursor moves with the mouse)
1375 		Sys_UpdateWindows( W_XY );
1376 	}
1377 }
1378 
1379 /*
1380  =======================================================================================================================
1381  =======================================================================================================================
1382  */
RetainClipMode(bool bMode)1383 void CXYWnd::RetainClipMode(bool bMode) {
1384 	bool	bSave = g_bRogueClipMode;
1385 	SetClipMode(bMode);
1386 	if (bMode == true) {
1387 		g_bRogueClipMode = bSave;
1388 	}
1389 	else {
1390 		g_bRogueClipMode = false;
1391 	}
1392 }
1393 
1394 /*
1395  =======================================================================================================================
1396  =======================================================================================================================
1397  */
SetClipMode(bool bMode)1398 void CXYWnd::SetClipMode(bool bMode) {
1399 	g_bClipMode = bMode;
1400 	g_bRogueClipMode = false;
1401 	if (bMode) {
1402 		g_Clip1.Reset();
1403 		g_Clip2.Reset();
1404 		g_Clip3.Reset();
1405 		CleanList(&g_brFrontSplits);
1406 		CleanList(&g_brBackSplits);
1407 		g_brFrontSplits.next = &g_brFrontSplits;
1408 		g_brBackSplits.next = &g_brBackSplits;
1409 	}
1410 	else {
1411 		if (g_pMovingClip) {
1412 			ReleaseCapture();
1413 			g_pMovingClip = NULL;
1414 		}
1415 
1416 		CleanList(&g_brFrontSplits);
1417 		CleanList(&g_brBackSplits);
1418 		g_brFrontSplits.next = &g_brFrontSplits;
1419 		g_brBackSplits.next = &g_brBackSplits;
1420 		Sys_UpdateWindows(XY | W_CAMERA_IFON);
1421 	}
1422 }
1423 
1424 /*
1425  =======================================================================================================================
1426  =======================================================================================================================
1427  */
ClipMode()1428 bool CXYWnd::ClipMode() {
1429 	return g_bClipMode;
1430 }
1431 
1432 /*
1433  =======================================================================================================================
1434  =======================================================================================================================
1435  */
RogueClipMode()1436 bool CXYWnd::RogueClipMode() {
1437 	return g_bRogueClipMode;
1438 }
1439 
1440 /*
1441  =======================================================================================================================
1442  =======================================================================================================================
1443  */
PathMode()1444 bool CXYWnd::PathMode() {
1445 	return g_bPathMode;
1446 }
1447 
1448 /*
1449  =======================================================================================================================
1450  =======================================================================================================================
1451  */
PointMode()1452 bool CXYWnd::PointMode() {
1453 	return g_bPointMode;
1454 }
1455 
1456 /*
1457  =======================================================================================================================
1458  =======================================================================================================================
1459  */
SetPointMode(bool b)1460 void CXYWnd::SetPointMode(bool b) {
1461 	g_bPointMode = b;
1462 	if (!b) {
1463 		g_nPointCount = 0;
1464 	}
1465 }
1466 
1467 /*
1468  =======================================================================================================================
1469  =======================================================================================================================
1470  */
OnPaint()1471 void CXYWnd::OnPaint() {
1472 	CPaintDC	dc(this);					// device context for painting
1473 	bool		bPaint = true;
1474 	if (!qwglMakeCurrent(dc.m_hDC, win32.hGLRC)) {
1475 		common->Printf("ERROR: wglMakeCurrent failed.. Error:%i\n", qglGetError());
1476 		common->Printf("Please restart Q3Radiant if the Map view is not working\n");
1477 		bPaint = false;
1478 	}
1479 
1480 	if (bPaint) {
1481 		QE_CheckOpenGLForErrors();
1482 		XY_Draw();
1483 		QE_CheckOpenGLForErrors();
1484 
1485 		if (m_nViewType != XY) {
1486 			qglPushMatrix();
1487 			if (m_nViewType == YZ) {
1488 				qglRotatef(-90, 0, 1, 0);	// put Z going up
1489 			}
1490 
1491 			qglRotatef(-90, 1, 0, 0);		// put Z going up
1492 		}
1493 
1494 		if ( g_bCrossHairs ) {
1495 			qglColor4f( 0.2f, 0.9f, 0.2f, 0.8f );
1496 			qglBegin(GL_LINES);
1497 			if (m_nViewType == XY) {
1498 				qglVertex2f(-16384, tdp[1]);
1499 				qglVertex2f(16384, tdp[1]);
1500 				qglVertex2f(tdp[0], -16384);
1501 				qglVertex2f(tdp[0], 16384);
1502 			}
1503 			else if (m_nViewType == YZ) {
1504 				qglVertex3f(tdp[0], -16384, tdp[2]);
1505 				qglVertex3f(tdp[0], 16384, tdp[2]);
1506 				qglVertex3f(tdp[0], tdp[1], -16384);
1507 				qglVertex3f(tdp[0], tdp[1], 16384);
1508 			}
1509 			else {
1510 				qglVertex3f(-16384, tdp[1], tdp[2]);
1511 				qglVertex3f(16384, tdp[1], tdp[2]);
1512 				qglVertex3f(tdp[0], tdp[1], -16384);
1513 				qglVertex3f(tdp[0], tdp[1], 16384);
1514 			}
1515 
1516 			qglEnd();
1517 		}
1518 
1519 		if (ClipMode()) {
1520 			qglPointSize(4);
1521 			qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER].ToFloatPtr());
1522 			qglBegin(GL_POINTS);
1523 			if (g_Clip1.Set()) {
1524 				qglVertex3fv(g_Clip1);
1525 			}
1526 
1527 			if (g_Clip2.Set()) {
1528 				qglVertex3fv(g_Clip2);
1529 			}
1530 
1531 			if (g_Clip3.Set()) {
1532 				qglVertex3fv(g_Clip3);
1533 			}
1534 
1535 			qglEnd();
1536 			qglPointSize(1);
1537 
1538 			CString strMsg;
1539 			if (g_Clip1.Set()) {
1540 				qglRasterPos3f(g_Clip1.m_ptClip[0] + 2, g_Clip1.m_ptClip[1] + 2, g_Clip1.m_ptClip[2] + 2);
1541 				strMsg = "1";
1542 
1543 				// strMsg.Format("1 (%f, %f, %f)", g_Clip1[0], g_Clip1[1], g_Clip1[2]);
1544 				qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
1545 			}
1546 
1547 			if (g_Clip2.Set()) {
1548 				qglRasterPos3f(g_Clip2.m_ptClip[0] + 2, g_Clip2.m_ptClip[1] + 2, g_Clip2.m_ptClip[2] + 2);
1549 				strMsg = "2";
1550 
1551 				// strMsg.Format("2 (%f, %f, %f)", g_Clip2[0], g_Clip2[1], g_Clip2[2]);
1552 				qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
1553 			}
1554 
1555 			if (g_Clip3.Set()) {
1556 				qglRasterPos3f(g_Clip3.m_ptClip[0] + 2, g_Clip3.m_ptClip[1] + 2, g_Clip3.m_ptClip[2] + 2);
1557 				strMsg = "3";
1558 
1559 				// strMsg.Format("3 (%f, %f, %f)", g_Clip3[0], g_Clip3[1], g_Clip3[2]);
1560 				qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
1561 			}
1562 
1563 			if (g_Clip1.Set() && g_Clip2.Set() && selected_brushes.next != &selected_brushes) {
1564 				ProduceSplitLists();
1565 
1566 				brush_t *pBrush;
1567 				brush_t *pList = ((m_nViewType == XZ) ? !g_bSwitch : g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits;
1568 				for (pBrush = pList->next; pBrush != NULL && pBrush != pList; pBrush = pBrush->next) {
1569 					qglColor3f(1, 1, 0);
1570 
1571 					face_t	*face;
1572 					int		order;
1573 					for (face = pBrush->brush_faces, order = 0; face; face = face->next, order++) {
1574 						idWinding *w = face->face_winding;
1575 						if (!w) {
1576 							continue;
1577 						}
1578 
1579 						// draw the polygon
1580 						qglBegin(GL_LINE_LOOP);
1581 						for (int i = 0; i < w->GetNumPoints(); i++) {
1582 							qglVertex3fv( (*w)[i].ToFloatPtr() );
1583 						}
1584 
1585 						qglEnd();
1586 					}
1587 				}
1588 			}
1589 		}
1590 
1591 		if (PathMode()) {
1592 			qglPointSize(4);
1593 			qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER].ToFloatPtr());
1594 			qglBegin(GL_POINTS);
1595 
1596 			int n;
1597 			for ( n = 0; n < g_nPathCount; n++) {
1598 				qglVertex3fv(g_PathPoints[n]);
1599 			}
1600 
1601 			qglEnd();
1602 			qglPointSize(1);
1603 
1604 			CString strMsg;
1605 			for (n = 0; n < g_nPathCount; n++) {
1606 				qglRasterPos3f
1607 				(
1608 					g_PathPoints[n].m_ptClip[0] + 2,
1609 					g_PathPoints[n].m_ptClip[1] + 2,
1610 					g_PathPoints[n].m_ptClip[2] + 2
1611 				);
1612 				strMsg.Format("%i", n + 1);
1613 				qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
1614 			}
1615 		}
1616 
1617 		if (m_nViewType != XY) {
1618 			qglPopMatrix();
1619 		}
1620 
1621 		qwglSwapBuffers(dc.m_hDC);
1622 		TRACE("XY Paint\n");
1623 	}
1624 }
1625 
1626 /*
1627  =======================================================================================================================
1628  =======================================================================================================================
1629  */
OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)1630 void CXYWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
1631 	g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags);
1632 }
1633 
1634 //
1635 // =======================================================================================================================
1636 //    FIXME: the brush_t *pBrush is never used. ( Entity_Create uses selected_brushes )
1637 // =======================================================================================================================
1638 //
CreateEntityFromName(char * pName,brush_t * pBrush,bool forceFixed,idVec3 min,idVec3 max,idVec3 org)1639 void CreateEntityFromName(char *pName, brush_t *pBrush, bool forceFixed, idVec3 min, idVec3 max, idVec3 org) {
1640 	eclass_t	*pecNew;
1641 	entity_t	*petNew;
1642 	if (stricmp(pName, "worldspawn") == 0) {
1643 		g_pParentWnd->MessageBox("Can't create an entity with worldspawn.", "info", 0);
1644 		return;
1645 	}
1646 
1647 	pecNew = Eclass_ForName(pName, false);
1648 
1649 	if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) {
1650 		Select_Ungroup();
1651 	}
1652 
1653 	// create it
1654 	petNew = Entity_Create(pecNew, forceFixed);
1655 
1656 	if (petNew && idStr::Icmp(pName, "light") == 0 ) {
1657 		idVec3	rad = max - min;
1658 		rad *= 0.5;
1659 		if (rad.x != 0 && rad.y != 0 && rad.z != 0) {
1660 			SetKeyValue(petNew, "light_radius", va("%g %g %g", idMath::Fabs(rad.x), idMath::Fabs(rad.y), idMath::Fabs(rad.z)));
1661 			DeleteKey(petNew, "light");
1662 		}
1663 	}
1664 
1665 
1666 	if (petNew == NULL) {
1667 		if (!((selected_brushes.next == &selected_brushes) || (selected_brushes.next->next != &selected_brushes))) {
1668 			brush_t *b = selected_brushes.next;
1669 			if (b->owner != world_entity && ((b->owner->eclass->fixedsize && pecNew->fixedsize) || forceFixed)) {
1670 				idVec3	mins, maxs;
1671 				idVec3	origin;
1672 				for (int i = 0; i < 3; i++) {
1673 					origin[i] = b->mins[i] - pecNew->mins[i];
1674 				}
1675 
1676 				VectorAdd(pecNew->mins, origin, mins);
1677 				VectorAdd(pecNew->maxs, origin, maxs);
1678 
1679 				brush_t *nb = Brush_Create(mins, maxs, &pecNew->texdef);
1680 				Entity_LinkBrush(b->owner, nb);
1681 				nb->owner->eclass = pecNew;
1682 				SetKeyValue(nb->owner, "classname", pName);
1683 				Brush_Free(b);
1684 				Brush_Build(nb);
1685 				Brush_AddToList(nb, &active_brushes);
1686 				Select_Brush(nb);
1687 				return;
1688 			}
1689 		}
1690 
1691 		g_pParentWnd->MessageBox("Failed to create entity.", "info", 0);
1692 		return;
1693 	}
1694 
1695 	Select_Deselect();
1696 
1697 	//
1698 	// entity_t* pEntity = world_entity; if (selected_brushes.next !=
1699 	// &selected_brushes) pEntity = selected_brushes.next->owner;
1700 	//
1701 	Select_Brush(petNew->brushes.onext);
1702 	Brush_Build(petNew->brushes.onext);
1703 
1704 }
1705 
1706 /*
1707  =======================================================================================================================
1708  =======================================================================================================================
1709  */
CreateEntityBrush(int x,int y,CXYWnd * pWnd)1710 brush_t *CreateEntityBrush(int x, int y, CXYWnd *pWnd) {
1711 	idVec3	mins, maxs;
1712 	int		i;
1713 	float	temp;
1714 	brush_t *n;
1715 
1716 	pWnd->SnapToPoint(x, y, mins);
1717 	x += 32;
1718 	y += 32;
1719 	pWnd->SnapToPoint(x, y, maxs);
1720 
1721 	int nDim = (pWnd->GetViewType() == XY) ? 2 : (pWnd->GetViewType() == YZ) ? 0 : 1;
1722 	mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom[nDim] / g_qeglobals.d_gridsize));
1723 	maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top[nDim] / g_qeglobals.d_gridsize));
1724 
1725 	if (maxs[nDim] <= mins[nDim]) {
1726 		maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize;
1727 	}
1728 
1729 	for (i = 0; i < 3; i++) {
1730 		if (mins[i] == maxs[i]) {
1731 			maxs[i] += 16;	// don't create a degenerate brush
1732 		}
1733 
1734 		if (mins[i] > maxs[i]) {
1735 			temp = mins[i];
1736 			mins[i] = maxs[i];
1737 			maxs[i] = temp;
1738 		}
1739 	}
1740 
1741 	n = Brush_Create(mins, maxs, &g_qeglobals.d_texturewin.texdef);
1742 	if (!n) {
1743 		return NULL;
1744 	}
1745 
1746 	Brush_AddToList(n, &selected_brushes);
1747 	Entity_LinkBrush(world_entity, n);
1748 	Brush_Build(n);
1749 	return n;
1750 }
1751 
1752 /*
1753  =======================================================================================================================
1754  =======================================================================================================================
1755  */
CreateRightClickEntity(CXYWnd * pWnd,int x,int y,char * pName)1756 void CreateRightClickEntity(CXYWnd *pWnd, int x, int y, char *pName) {
1757 	idVec3	min, max, org;
1758 	Select_GetBounds(min, max);
1759 	Select_GetMid(org);
1760 
1761 	CRect	rctZ;
1762 	pWnd->GetClientRect(rctZ);
1763 
1764 	brush_t *pBrush;
1765 	if (selected_brushes.next == &selected_brushes) {
1766 		pBrush = CreateEntityBrush(x, rctZ.Height() - 1 - y, pWnd);
1767 		min.Zero();
1768 		max.Zero();
1769 		CreateEntityFromName(pName, pBrush, true, min, max, org);
1770 	}
1771 	else {
1772 		pBrush = selected_brushes.next;
1773 		CreateEntityFromName(pName, pBrush, false, min, max, org);
1774 	}
1775 }
1776 
1777 /*
1778  =======================================================================================================================
1779  =======================================================================================================================
1780  */
CreateSmartBrush(idVec3 v)1781 brush_t *CreateSmartBrush(idVec3 v) {
1782 	idVec3	mins, maxs;
1783 	int		i;
1784 	brush_t *n;
1785 
1786 	for (i = 0; i < 3; i++) {
1787 		mins[i] = v[i] - 16;
1788 		maxs[i] = v[i] + 16;
1789 	}
1790 
1791 	n = Brush_Create(mins, maxs, &g_qeglobals.d_texturewin.texdef);
1792 	if (!n) {
1793 		return NULL;
1794 	}
1795 
1796 	Brush_AddToList(n, &selected_brushes);
1797 
1798 	// Entity_LinkBrush(world_entity, n);
1799 	Brush_Build(n);
1800 	return n;
1801 }
1802 
1803 CString g_strSmartEntity;
1804 int		g_nSmartX;
1805 int		g_nSmartY;
1806 bool	g_bSmartWaiting;
1807 
1808 /*
1809  =======================================================================================================================
1810  =======================================================================================================================
1811  */
_SmartPointDone(bool b,int n)1812 void _SmartPointDone(bool b, int n) {
1813 	g_bSmartWaiting = false;
1814 }
1815 
1816 /*
1817  =======================================================================================================================
1818  =======================================================================================================================
1819  */
CreateSmartEntity(CXYWnd * pWnd,int x,int y,const char * pName)1820 void CreateSmartEntity(CXYWnd *pWnd, int x, int y, const char *pName) {
1821 	g_nSmartX = x;
1822 	g_nSmartY = y;
1823 	g_strSmartEntity = pName;
1824 	if (g_strSmartEntity.Find("Smart_Train") >= 0) {
1825 		ShowInfoDialog("Select the path of the train by left clicking in XY, YZ and/or XZ views. You can move an already dropped point by grabbing and moving it. When you are finished, press ENTER to accept and create the entity and path(s), press ESC to abandon the creation");
1826 		g_bPathMode = true;
1827 		g_nPathLimit = 0;
1828 		g_nPathCount = 0;
1829 		g_bSmartGo = true;
1830 	}
1831 	else if (g_strSmartEntity.Find("Smart_Monster...") >= 0) {
1832 		g_bPathMode = true;
1833 		g_nPathLimit = 0;
1834 		g_nPathCount = 0;
1835 	}
1836 	else if (g_strSmartEntity.Find("Smart_Rotating") >= 0) {
1837 		g_bSmartWaiting = true;
1838 		ShowInfoDialog("Left click to specify the rotation origin");
1839 		AcquirePath(1, &_SmartPointDone);
1840 		while (g_bSmartWaiting) {
1841 			MSG msg;
1842 			if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1843 				TranslateMessage(&msg);
1844 				DispatchMessage(&msg);
1845 			}
1846 		}
1847 
1848 		HideInfoDialog();
1849 
1850 		CPtrArray	array;
1851 		g_bScreenUpdates = false;
1852 		CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_rotating");
1853 		array.Add(reinterpret_cast < void * > (selected_brushes.next));
1854 		Select_Deselect();
1855 
1856 		brush_t *pBrush = CreateSmartBrush(g_PathPoints[0]);
1857 		array.Add(pBrush);
1858 		Select_Deselect();
1859 		Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(0)));
1860 		Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(1)));
1861 		ConnectEntities();
1862 		g_bScreenUpdates = true;
1863 	}
1864 }
1865 
1866 /*
1867  =======================================================================================================================
1868  =======================================================================================================================
1869  */
FinishSmartCreation()1870 void FinishSmartCreation() {
1871 	CPtrArray	array;
1872 	HideInfoDialog();
1873 
1874 	brush_t *pEntities = NULL;
1875 	if (g_strSmartEntity.Find("Smart_Train") >= 0) {
1876 		g_bScreenUpdates = false;
1877 		CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_train");
1878 		array.Add(reinterpret_cast < void * > (selected_brushes.next));
1879 		int n;
1880 		for (n = 0; n < g_nPathCount; n++) {
1881 			Select_Deselect();
1882 			CreateRightClickEntity
1883 			(
1884 				g_pParentWnd->ActiveXY(),
1885 				g_PathPoints[n].m_ptScreen.x,
1886 				g_PathPoints[n].m_ptScreen.y,
1887 				"path_corner"
1888 			);
1889 			array.Add(reinterpret_cast < void * > (selected_brushes.next));
1890 		}
1891 
1892 		for (n = 0; n < g_nPathCount; n++) {
1893 			Select_Deselect();
1894 			Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(n)));
1895 			Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(n + 1)));
1896 			ConnectEntities();
1897 		}
1898 
1899 		g_bScreenUpdates = true;
1900 	}
1901 
1902 	g_nPathCount = 0;
1903 	g_bPathMode = false;
1904 	Sys_UpdateWindows(W_ALL);
1905 }
1906 
1907 /*
1908  =======================================================================================================================
1909  =======================================================================================================================
1910  */
KillPathMode()1911 void CXYWnd::KillPathMode() {
1912 	g_bSmartGo = false;
1913 	g_bPathMode = false;
1914 	if (g_pPathFunc) {
1915 		g_pPathFunc(false, g_nPathCount);
1916 	}
1917 
1918 	g_nPathCount = 0;
1919 	g_pPathFunc = NULL;
1920 	Sys_UpdateWindows(W_ALL);
1921 }
1922 
1923 //
1924 // =======================================================================================================================
1925 //    gets called for drop down menu messages TIP: it's not always about EntityCreate
1926 // =======================================================================================================================
1927 //
OnEntityCreate(unsigned int nID)1928 void CXYWnd::OnEntityCreate(unsigned int nID) {
1929 	if (m_mnuDrop.GetSafeHmenu()) {
1930 		CString strItem;
1931 		m_mnuDrop.GetMenuString(nID, strItem, MF_BYCOMMAND);
1932 
1933 		if (strItem.CompareNoCase("Add to...") == 0) {
1934 			//
1935 			// ++timo TODO: fill the menu with current groups? this one is for adding to
1936 			// existing groups only
1937 			//
1938 			common->Printf("TODO: Add to... in CXYWnd::OnEntityCreate\n");
1939 		}
1940 		else if (strItem.CompareNoCase("Remove") == 0) {
1941 			// remove selected brushes from their current group
1942 			brush_t *b;
1943 			for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
1944 			}
1945 		}
1946 
1947 		// ++timo FIXME: remove when all hooks are in
1948 		if
1949 		(
1950 			strItem.CompareNoCase("Add to...") == 0 ||
1951 			strItem.CompareNoCase("Remove") == 0 ||
1952 			strItem.CompareNoCase("Name...") == 0 ||
1953 			strItem.CompareNoCase("New group...") == 0
1954 		) {
1955 			common->Printf("TODO: hook drop down group menu\n");
1956 			return;
1957 		}
1958 
1959 		if (strItem.Find("Smart_") >= 0) {
1960 			CreateSmartEntity(this, m_ptDown.x, m_ptDown.y, strItem);
1961 		}
1962 		else {
1963 			CreateRightClickEntity(this, m_ptDown.x, m_ptDown.y, strItem.GetBuffer(0));
1964 		}
1965 
1966 		Sys_UpdateWindows(W_ALL);
1967 
1968 		// OnLButtonDown((MK_LBUTTON | MK_SHIFT), CPoint(m_ptDown.x+2, m_ptDown.y+2));
1969 	}
1970 }
1971 
OnCmdMsg(UINT nID,int nCode,void * pExtra,AFX_CMDHANDLERINFO * pHandlerInfo)1972 BOOL CXYWnd::OnCmdMsg( UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo )
1973 {
1974 	if ( CWnd::OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ) ) {
1975 		return TRUE;
1976 	}
1977 	return AfxGetMainWnd()->OnCmdMsg( nID, nCode, pExtra, pHandlerInfo );
1978 }
1979 
MergeMenu(CMenu * pMenuDestination,const CMenu * pMenuAdd,bool bTopLevel)1980 bool MergeMenu(CMenu * pMenuDestination, const CMenu * pMenuAdd, bool bTopLevel /*=false*/)
1981 {
1982 	// get the number menu items in the menus
1983 	int iMenuAddItemCount	= pMenuAdd->GetMenuItemCount();
1984 	int iMenuDestItemCount	= pMenuDestination->GetMenuItemCount();
1985 
1986 	// if there are no items return
1987 	if (iMenuAddItemCount == 0)
1988 		return true;
1989 
1990 	// if we are not at top level and the destination menu is not empty
1991 	// -> we append a seperator
1992 	if (!bTopLevel && iMenuDestItemCount > 0)
1993 		pMenuDestination->AppendMenu(MF_SEPARATOR);
1994 
1995 	// iterate through the top level of <pMenuAdd>
1996 	for(int iLoop = 0; iLoop < iMenuAddItemCount; iLoop++)
1997 	{
1998 		// get the menu string from the add menu
1999 		CString sMenuAddString;
2000 		pMenuAdd->GetMenuString(iLoop, sMenuAddString, MF_BYPOSITION);
2001 
2002 		// try to get the submenu of the current menu item
2003 		CMenu* pSubMenu = pMenuAdd->GetSubMenu(iLoop);
2004 
2005 		// check if we have a sub menu
2006 		if (!pSubMenu)
2007 		{
2008 			// normal menu item
2009 			// read the source and append at the destination
2010 			UINT nState	 = pMenuAdd->GetMenuState(iLoop, MF_BYPOSITION);
2011 			UINT nItemID = pMenuAdd->GetMenuItemID(iLoop);
2012 			if (pMenuDestination->AppendMenu(nState, nItemID, sMenuAddString))
2013 			{
2014 				// menu item added, don't forget to correct the item count
2015 				iMenuDestItemCount++;
2016 			}
2017 			else
2018 			{
2019 				TRACE("MergeMenu: AppendMenu failed!\n");
2020 				return false;
2021 			}
2022 		}
2023 		else
2024 		{
2025 			// create or insert a new popup menu item
2026 
2027 			// default insert pos is like ap
2028 			int iInsertPosDefault = -1;
2029 
2030 			// if we are at top level merge into existing popups rather than
2031 			// creating new ones
2032 			if(bTopLevel)
2033 			{
2034 				ASSERT(sMenuAddString != "&?" && sMenuAddString !=
2035 					"?");
2036 				CString csAdd(sMenuAddString);
2037 				csAdd.Remove('&');	// for comparison of menu items supress '&'
2038 				bool bAdded = false;
2039 
2040 				// try to find existing popup
2041 				for( int iLoop1 = 0; iLoop1 < iMenuDestItemCount; iLoop1++ )
2042 				{
2043 					// get the menu string from the destination menu
2044 					CString sDest;
2045 					pMenuDestination->GetMenuString(iLoop1, sDest, MF_BYPOSITION);
2046 					sDest.Remove('&'); // for a better compare (s.a.)
2047 
2048 					if (csAdd == sDest)
2049 					{
2050 						// we got a hit -> merge the two popups
2051 						// try to get the submenu of the desired destination menu item
2052 							CMenu* pSubMenuDest =
2053 							pMenuDestination->GetSubMenu(iLoop1);
2054 
2055 						if (pSubMenuDest)
2056 						{
2057 							// merge the popup recursivly and continue with outer for loop
2058 								if (!MergeMenu(pSubMenuDest, pSubMenu, false))
2059 									return false;
2060 							bAdded = true;
2061 							break;
2062 						}
2063 					}
2064 
2065 					// alternativ insert before <Window> or <Help>
2066 					if (iInsertPosDefault == -1 && (sDest == "Window"
2067 						|| sDest == "?" || sDest == "Help"))
2068 					{
2069 						iInsertPosDefault = iLoop1;
2070 					}
2071 				} // for (iLoop1)
2072 				if (bAdded)
2073 				{
2074 					// menu added, so go on with loop over pMenuAdd's top level
2075 					continue;
2076 				}
2077 			} // if (bTopLevel)
2078 
2079 			// if the top level search did not find a position append the menu
2080 			if( iInsertPosDefault == -1 )
2081 			{
2082 				iInsertPosDefault = pMenuDestination->GetMenuItemCount();
2083 			}
2084 
2085 			// create a new popup and insert before <Window> or <Help>
2086 			CMenu NewPopupMenu;
2087 			if (!NewPopupMenu.CreatePopupMenu())
2088 			{
2089 				TRACE("MergeMenu: CreatePopupMenu failed!\n");
2090 				return false;
2091 			}
2092 
2093 			// merge the new popup recursivly
2094 			if (!MergeMenu(&NewPopupMenu, pSubMenu, false))
2095 				return false;
2096 
2097 			// insert the new popup menu into the destination menu
2098 			HMENU hNewMenu = NewPopupMenu.GetSafeHmenu();
2099 			if (pMenuDestination->InsertMenu(iInsertPosDefault,
2100 				MF_BYPOSITION | MF_POPUP | MF_ENABLED,
2101 				(UINT)hNewMenu, sMenuAddString ))
2102 			{
2103 				// don't forget to correct the item count
2104 				iMenuDestItemCount++;
2105 			}
2106 			else
2107 			{
2108 				TRACE("MergeMenu: InsertMenu failed!\n");
2109 				return false;
2110 			}
2111 
2112 			// don't destroy the new menu
2113 			NewPopupMenu.Detach();
2114 		} // if (pSubMenu)
2115 	} // for (iLoop)
2116 	return true;
2117 }
2118 
2119 
2120 
2121 
2122 /*
2123  =======================================================================================================================
2124  =======================================================================================================================
2125  */
HandleDrop()2126 void CXYWnd::HandleDrop() {
2127 	if (g_PrefsDlg.m_bRightClick == false) {
2128 		return;
2129 	}
2130 
2131 	if (!m_mnuDrop.GetSafeHmenu()) {		// first time, load it up
2132 		m_mnuDrop.CreatePopupMenu();
2133 
2134 		CMenu *drop = new CMenu;
2135 		drop->LoadMenu( IDR_MENU_DROP );
2136 
2137 		MergeMenu( &m_mnuDrop, drop, false );
2138 
2139 		int		nID = ID_ENTITY_START;
2140 
2141 		CMenu	*pMakeEntityPop = &m_mnuDrop;
2142 
2143 		// Todo: Make this a config option maybe?
2144 		const int entitiesOnSubMenu = false;
2145 		if ( entitiesOnSubMenu ) {
2146 			pMakeEntityPop = new CMenu;
2147 			pMakeEntityPop->CreateMenu();
2148 		}
2149 
2150 		CMenu	*pChild = NULL;
2151 
2152 		eclass_t	*e;
2153 		CString		strActive;
2154 		CString		strLast;
2155 		CString		strName;
2156 		for (e = eclass; e; e = e->next) {
2157 			strLast = strName;
2158 			strName = e->name;
2159 
2160 			int n_ = strName.Find("_");
2161 			if (n_ > 0) {
2162 				CString strLeft = strName.Left(n_);
2163 				CString strRight = strName.Right(strName.GetLength() - n_ - 1);
2164 				if (strLeft == strActive) { // this is a child
2165 					ASSERT(pChild);
2166 					pChild->AppendMenu(MF_STRING, nID++, strName);
2167 				}
2168 				else {
2169 					if (pChild) {
2170 						pMakeEntityPop->AppendMenu (
2171 							MF_POPUP,
2172 							reinterpret_cast < unsigned int > (pChild->GetSafeHmenu()),
2173 							strActive
2174 						);
2175 						g_ptrMenus.Add(pChild);
2176 
2177 						// pChild->DestroyMenu(); delete pChild;
2178 						pChild = NULL;
2179 					}
2180 
2181 					strActive = strLeft;
2182 					pChild = new CMenu;
2183 					pChild->CreateMenu();
2184 					pChild->AppendMenu(MF_STRING, nID++, strName);
2185 				}
2186 			}
2187 			else {
2188 				if (pChild) {
2189 					pMakeEntityPop->AppendMenu (
2190 						MF_POPUP,
2191 						reinterpret_cast < unsigned int > (pChild->GetSafeHmenu()),
2192 						strActive
2193 					);
2194 					g_ptrMenus.Add(pChild);
2195 
2196 					// pChild->DestroyMenu(); delete pChild;
2197 					pChild = NULL;
2198 				}
2199 
2200 				strActive = "";
2201 				pMakeEntityPop->AppendMenu(MF_STRING, nID++, strName);
2202 			}
2203 		}
2204 		if ( pMakeEntityPop != &m_mnuDrop ) {
2205 			m_mnuDrop.AppendMenu (
2206 				MF_POPUP,
2207 				reinterpret_cast < unsigned int > (pMakeEntityPop->GetSafeHmenu()),
2208 				"Make Entity"
2209 			);
2210 		}
2211 	}
2212 
2213 	CPoint	ptMouse;
2214 	GetCursorPos(&ptMouse);
2215 	m_mnuDrop.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, ptMouse.x, ptMouse.y, this);
2216 }
2217 
2218 /*
2219  =======================================================================================================================
2220  =======================================================================================================================
2221  */
XY_Init()2222 void CXYWnd::XY_Init() {
2223 	m_vOrigin[0] = 0;
2224 	m_vOrigin[1] = 20;
2225 	m_vOrigin[2] = 46;
2226 	m_fScale = 1;
2227 	m_precisionCrosshairMode = PRECISION_CROSSHAIR_NONE;
2228 }
2229 
2230 /*
2231  =======================================================================================================================
2232  =======================================================================================================================
2233  */
SnapToPoint(int x,int y,idVec3 & point)2234 void CXYWnd::SnapToPoint(int x, int y, idVec3 &point) {
2235 	if (g_PrefsDlg.m_bNoClamp) {
2236 		XY_ToPoint(x, y, point);
2237 	}
2238 	else {
2239 		XY_ToGridPoint(x, y, point);
2240 	}
2241 
2242 	// -- else -- XY_ToPoint(x, y, point); -- //XY_ToPoint(x, y, point);
2243 }
2244 
2245 /*
2246  =======================================================================================================================
2247  =======================================================================================================================
2248  */
XY_ToPoint(int x,int y,idVec3 & point)2249 void CXYWnd::XY_ToPoint(int x, int y, idVec3 &point) {
2250 	float	fx = x;
2251 	float	fy = y;
2252 	float	fw = m_nWidth;
2253 	float	fh = m_nHeight;
2254 	if (m_nViewType == XY) {
2255 		point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale;
2256 		point[1] = m_vOrigin[1] + (fy - fh / 2) / m_fScale;
2257 
2258 		// point[2] = 0;
2259 	}
2260 	else if (m_nViewType == YZ) {
2261 		//
2262 		// //point[0] = 0; point[1] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; point[2] =
2263 		// m_vOrigin[1] + (fy - fh / 2 ) / m_fScale;
2264 		//
2265 		point[1] = m_vOrigin[1] + (fx - fw / 2) / m_fScale;
2266 		point[2] = m_vOrigin[2] + (fy - fh / 2) / m_fScale;
2267 	}
2268 	else {
2269 		//
2270 		// point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; /point[1] = 0; point[2] =
2271 		// m_vOrigin[1] + (fy - fh / 2) / m_fScale;
2272 		//
2273 		point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale;
2274 
2275 		// point[1] = 0;
2276 		point[2] = m_vOrigin[2] + (fy - fh / 2) / m_fScale;
2277 	}
2278 }
2279 
2280 /*
2281  =======================================================================================================================
2282  =======================================================================================================================
2283  */
XY_ToGridPoint(int x,int y,idVec3 & point)2284 void CXYWnd::XY_ToGridPoint(int x, int y, idVec3 &point) {
2285 	if (m_nViewType == XY) {
2286 		point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale;
2287 		point[1] = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale;
2288 
2289 		// point[2] = 0;
2290 		point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2291 		point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2292 	}
2293 	else if (m_nViewType == YZ) {
2294 		//
2295 		// point[0] = 0; point[1] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; point[2]
2296 		// = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale;
2297 		//
2298 		point[1] = m_vOrigin[1] + (x - m_nWidth / 2) / m_fScale;
2299 		point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale;
2300 		point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2301 		point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2302 	}
2303 	else {
2304 		//
2305 		// point[1] = 0; point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; point[2]
2306 		// = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale;
2307 		//
2308 		point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale;
2309 		point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale;
2310 		point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2311 		point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2312 	}
2313 }
2314 
2315 /*
2316  =======================================================================================================================
2317  =======================================================================================================================
2318  */
2319 idVec3 dragOrigin;
2320 idVec3 dragDir;
2321 idVec3 dragX;
2322 idVec3 dragY;
2323 
XY_MouseDown(int x,int y,int buttons)2324 void CXYWnd::XY_MouseDown(int x, int y, int buttons) {
2325 	idVec3	point,center;
2326 	idVec3	origin, dir, right, up;
2327 
2328 	m_nButtonstate = buttons;
2329 	m_nPressx = x;
2330 	m_nPressy = y;
2331 	VectorCopy(vec3_origin, m_vPressdelta);
2332 
2333 	point.Zero();
2334 
2335 	XY_ToPoint(x, y, point);
2336 
2337 	VectorCopy(point, origin);
2338 
2339 	dir.Zero();
2340 	if (m_nViewType == XY) {
2341 		origin[2] = HUGE_DISTANCE;
2342 		dir[2] = -1;
2343 		right[0] = 1 / m_fScale;
2344 		right[1] = 0;
2345 		right[2] = 0;
2346 		up[0] = 0;
2347 		up[1] = 1 / m_fScale;
2348 		up[2] = 0;
2349 		point[2] = g_pParentWnd->GetCamera()->Camera().origin[2];
2350 	}
2351 	else if (m_nViewType == YZ) {
2352 		origin[0] = HUGE_DISTANCE;
2353 		dir[0] = -1;
2354 		right[1] = 1 / m_fScale;
2355 		right[2] = 0;
2356 		right[0] = 0;
2357 		up[0] = 0;
2358 		up[2] = 1 / m_fScale;
2359 		up[1] = 0;
2360 		point[0] = g_pParentWnd->GetCamera()->Camera().origin[0];
2361 	}
2362 	else {
2363 		origin[1] = HUGE_DISTANCE;
2364 		dir[1] = -1;
2365 		right[0] = 1 / m_fScale;
2366 		right[2] = 0;
2367 		right[1] = 0;
2368 		up[0] = 0;
2369 		up[2] = 1 / m_fScale;
2370 		up[1] = 0;
2371 		point[1] = g_pParentWnd->GetCamera()->Camera().origin[1];
2372 	}
2373 
2374 	dragOrigin = m_vOrigin;
2375 	dragDir = dir;
2376 	dragX = right;
2377 	dragY = up;
2378 
2379 	m_bPress_selection = (selected_brushes.next != &selected_brushes);
2380 
2381 	GetCursorPos(&m_ptCursor);
2382 
2383 	// Sys_GetCursorPos (&m_ptCursor.x, &m_ptCursor.y);
2384 	if (buttons == MK_LBUTTON && activeDrag) {
2385 		activeDragging = true;
2386 	}
2387 	else {
2388 		activeDragging = false;
2389 	}
2390 
2391 	// lbutton = manipulate selection shift-LBUTTON = select
2392 	if
2393 	(
2394 		(buttons == MK_LBUTTON) ||
2395 		(buttons == (MK_LBUTTON | MK_SHIFT)) ||
2396 		(buttons == (MK_LBUTTON | MK_CONTROL)) ||
2397 		(buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT))
2398 	) {
2399 		if (g_qeglobals.d_select_mode == sel_addpoint) {
2400 			XY_ToGridPoint(x, y, point);
2401 			if (g_qeglobals.selectObject) {
2402 				g_qeglobals.selectObject->addPoint(point);
2403 			}
2404 
2405 			return;
2406 		}
2407 
2408 		Patch_SetView((m_nViewType == XY) ? W_XY : (m_nViewType == YZ) ? W_YZ : W_XZ);
2409 		Drag_Begin(x, y, buttons, right, up, origin, dir);
2410 		return;
2411 	}
2412 
2413 	int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
2414 
2415 	// control mbutton = move camera
2416 	if (m_nButtonstate == (MK_CONTROL | nMouseButton)) {
2417 		VectorCopyXY(point, g_pParentWnd->GetCamera()->Camera().origin);
2418 		Sys_UpdateWindows(W_CAMERA | W_XY_OVERLAY);
2419 	}
2420 
2421 	// mbutton = angle camera
2422 	if
2423 	(
2424 		(g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) ||
2425 		(g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT | MK_CONTROL | MK_RBUTTON))
2426 	) {
2427 		VectorSubtract(point, g_pParentWnd->GetCamera()->Camera().origin, point);
2428 
2429 		int n1 = (m_nViewType == XY) ? 1 : 2;
2430 		int n2 = (m_nViewType == YZ) ? 1 : 0;
2431 		int nAngle = (m_nViewType == XY) ? YAW : PITCH;
2432 		if (point[n1] || point[n2]) {
2433 			g_pParentWnd->GetCamera()->Camera().angles[nAngle] = RAD2DEG( atan2(point[n1], point[n2]) );
2434 			Sys_UpdateWindows(W_CAMERA_IFON | W_XY_OVERLAY);
2435 		}
2436 	}
2437 
2438 	// shift mbutton = move z checker
2439 	if (m_nButtonstate == (MK_SHIFT | nMouseButton)) {
2440 		if (RotateMode() || g_bPatchBendMode) {
2441 			SnapToPoint(x, y, point);
2442 			VectorCopyXY(point, g_vRotateOrigin);
2443 			if (g_bPatchBendMode) {
2444 				VectorCopy(point, g_vBendOrigin);
2445 			}
2446 
2447 			Sys_UpdateWindows(W_XY);
2448 			return;
2449 		}
2450 		else {
2451 			SnapToPoint(x, y, point);
2452 			if (m_nViewType == XY) {
2453 				z.origin[0] = point[0];
2454 				z.origin[1] = point[1];
2455 			}
2456 			else if (m_nViewType == YZ) {
2457 				z.origin[0] = point[1];
2458 				z.origin[1] = point[2];
2459 			}
2460 			else {
2461 				z.origin[0] = point[0];
2462 				z.origin[1] = point[2];
2463 			}
2464 
2465 			Sys_UpdateWindows(W_XY_OVERLAY | W_Z);
2466 			return;
2467 		}
2468 	}
2469 }
2470 
2471 /*
2472  =======================================================================================================================
2473  =======================================================================================================================
2474  */
XY_MouseUp(int x,int y,int buttons)2475 void CXYWnd::XY_MouseUp(int x, int y, int buttons) {
2476 	activeDragging = false;
2477 	Drag_MouseUp(buttons);
2478 	if (!m_bPress_selection) {
2479 		Sys_UpdateWindows(W_ALL);
2480 	}
2481 
2482 	m_nButtonstate = 0;
2483 	while (::ShowCursor(TRUE) < 0)
2484 		;
2485 }
2486 
2487 /*
2488  =======================================================================================================================
2489  =======================================================================================================================
2490  */
DragDelta(int x,int y,idVec3 & move)2491 bool CXYWnd::DragDelta(int x, int y, idVec3 &move) {
2492 	idVec3	xvec, yvec, delta;
2493 	int		i;
2494 
2495 	xvec[0] = 1 / m_fScale;
2496 	xvec[1] = xvec[2] = 0;
2497 	yvec[1] = 1 / m_fScale;
2498 	yvec[0] = yvec[2] = 0;
2499 
2500 	for (i = 0; i < 3; i++) {
2501 		delta[i] = xvec[i] * (x - m_nPressx) + yvec[i] * (y - m_nPressy);
2502 		if (!g_PrefsDlg.m_bNoClamp) {
2503 			delta[i] = floor(delta[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2504 		}
2505 	}
2506 
2507 	VectorSubtract(delta, m_vPressdelta, move);
2508 	VectorCopy(delta, m_vPressdelta);
2509 
2510 
2511 	if (move[0] || move[1] || move[2]) {
2512 		return true;
2513 	}
2514 
2515 	return false;
2516 }
2517 
2518 /*
2519  =======================================================================================================================
2520 	NewBrushDrag
2521  =======================================================================================================================
2522  */
NewBrushDrag(int x,int y)2523 void CXYWnd::NewBrushDrag(int x, int y) {
2524 	idVec3	mins, maxs, junk;
2525 	int		i;
2526 	float	temp;
2527 	brush_t *n;
2528 
2529 	if ( radiant_entityMode.GetBool() ) {
2530 		return;
2531 	}
2532 
2533 	if (!DragDelta(x, y, junk)) {
2534 		return;
2535 	}
2536 
2537 	// delete the current selection
2538 	if (selected_brushes.next != &selected_brushes) {
2539 		Brush_Free(selected_brushes.next);
2540 	}
2541 
2542 	SnapToPoint(m_nPressx, m_nPressy, mins);
2543 
2544 	int nDim = (m_nViewType == XY) ? 2 : (m_nViewType == YZ) ? 0 : 1;
2545 
2546 	mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom[nDim] / g_qeglobals.d_gridsize));
2547 	SnapToPoint(x, y, maxs);
2548 	maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top[nDim] / g_qeglobals.d_gridsize));
2549 	if (maxs[nDim] <= mins[nDim]) {
2550 		maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize;
2551 	}
2552 
2553 	for (i = 0; i < 3; i++) {
2554 		if (mins[i] == maxs[i]) {
2555 			return; // don't create a degenerate brush
2556 		}
2557 
2558 		if (mins[i] > maxs[i]) {
2559 			temp = mins[i];
2560 			mins[i] = maxs[i];
2561 			maxs[i] = temp;
2562 		}
2563 	}
2564 
2565 	n = Brush_Create(mins, maxs, &g_qeglobals.d_texturewin.texdef);
2566 	if (!n) {
2567 		return;
2568 	}
2569 
2570 	idVec3	vSize;
2571 	VectorSubtract(maxs, mins, vSize);
2572 	g_strStatus.Format("Size X:: %.1f  Y:: %.1f  Z:: %.1f", vSize[0], vSize[1], vSize[2]);
2573 	g_pParentWnd->SetStatusText(2, g_strStatus);
2574 
2575 	Brush_AddToList(n, &selected_brushes);
2576 
2577 	Entity_LinkBrush(world_entity, n);
2578 
2579 	Brush_Build(n);
2580 
2581 	// Sys_UpdateWindows (W_ALL);
2582 	Sys_UpdateWindows(W_XY | W_CAMERA);
2583 }
2584 
2585 /*
2586  =======================================================================================================================
2587 	XY_MouseMoved
2588  =======================================================================================================================
2589  */
XY_MouseMoved(int x,int y,int buttons)2590 bool CXYWnd::XY_MouseMoved(int x, int y, int buttons) {
2591 	idVec3	point;
2592 
2593 	if (!m_nButtonstate) {
2594 		if (g_bCrossHairs) {
2595 			::ShowCursor(FALSE);
2596 			Sys_UpdateWindows(W_XY | W_XY_OVERLAY);
2597 			::ShowCursor(TRUE);
2598 		}
2599 
2600 		return false;
2601 	}
2602 
2603 	//
2604 	// lbutton without selection = drag new brush if (m_nButtonstate == MK_LBUTTON &&
2605 	// !m_bPress_selection && g_qeglobals.d_select_mode != sel_curvepoint &&
2606 	// g_qeglobals.d_select_mode != sel_splineedit)
2607 	//
2608 	if (m_nButtonstate == MK_LBUTTON && !m_bPress_selection && g_qeglobals.d_select_mode == sel_brush) {
2609 		NewBrushDrag(x, y);
2610 		return false;
2611 	}
2612 
2613 	// lbutton (possibly with control and or shift) with selection = drag selection
2614 	if (m_nButtonstate & MK_LBUTTON) {
2615 		Drag_MouseMoved(x, y, buttons);
2616 		Sys_UpdateWindows(W_XY_OVERLAY | W_CAMERA_IFON | W_Z);
2617 		return false;
2618 	}
2619 
2620 	int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
2621 
2622 	// control mbutton = move camera
2623 	if (m_nButtonstate == (MK_CONTROL | nMouseButton)) {
2624 		SnapToPoint(x, y, point);
2625 		VectorCopyXY(point, g_pParentWnd->GetCamera()->Camera().origin);
2626 		Sys_UpdateWindows(W_XY_OVERLAY | W_CAMERA);
2627 		return false;
2628 	}
2629 
2630 	// shift mbutton = move z checker
2631 	if (m_nButtonstate == (MK_SHIFT | nMouseButton)) {
2632 		if (RotateMode() || g_bPatchBendMode) {
2633 			SnapToPoint(x, y, point);
2634 			VectorCopyXY(point, g_vRotateOrigin);
2635 			if (g_bPatchBendMode) {
2636 				VectorCopy(point, g_vBendOrigin);
2637 			}
2638 
2639 			Sys_UpdateWindows(W_XY);
2640 			return false;
2641 		}
2642 		else {
2643 			SnapToPoint(x, y, point);
2644 			if (m_nViewType == XY) {
2645 				z.origin[0] = point[0];
2646 				z.origin[1] = point[1];
2647 			}
2648 			else if (m_nViewType == YZ) {
2649 				z.origin[0] = point[1];
2650 				z.origin[1] = point[2];
2651 			}
2652 			else {
2653 				z.origin[0] = point[0];
2654 				z.origin[1] = point[2];
2655 			}
2656 		}
2657 
2658 		Sys_UpdateWindows(W_XY_OVERLAY | W_Z);
2659 		return false;
2660 	}
2661 
2662 	// mbutton = angle camera
2663 	if
2664 	(
2665 		(g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) ||
2666 		(g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT | MK_CONTROL | MK_RBUTTON))
2667 	) {
2668 		SnapToPoint(x, y, point);
2669 		VectorSubtract(point, g_pParentWnd->GetCamera()->Camera().origin, point);
2670 
2671 		int n1 = (m_nViewType == XY) ? 1 : 2;
2672 		int n2 = (m_nViewType == YZ) ? 1 : 0;
2673 		int nAngle = (m_nViewType == XY) ? YAW : PITCH;
2674 		if (point[n1] || point[n2]) {
2675 			g_pParentWnd->GetCamera()->Camera().angles[nAngle] = RAD2DEG( atan2(point[n1], point[n2]) );
2676 			Sys_UpdateWindows(W_CAMERA_IFON | W_XY_OVERLAY);
2677 		}
2678 
2679 		return false;
2680 	}
2681 
2682 	// rbutton = drag xy origin
2683 	if (m_nButtonstate == MK_RBUTTON) {
2684 		Sys_GetCursorPos(&x, &y);
2685 
2686 		if (x != m_ptCursor.x || y != m_ptCursor.y) {
2687 			if ((GetAsyncKeyState(VK_MENU) & 0x8000)) {
2688 				int		*px = &x;
2689 				long	*px2 = &m_ptCursor.x;
2690 
2691 				if (fDiff(y, m_ptCursor.y) > fDiff(x, m_ptCursor.x)) {
2692 					px = &y;
2693 					px2 = &m_ptCursor.y;
2694 				}
2695 
2696 				if (*px > *px2) {
2697 					// zoom in
2698 					SetScale( Scale() * 1.1f );
2699 					if ( Scale() < 0.1f ) {
2700 						SetScale( 0.1f );
2701 					}
2702 				}
2703 				else if (*px < *px2) {
2704 					// zoom out
2705 					SetScale( Scale() * 0.9f );
2706 					if ( Scale() > 16.0f ) {
2707 						SetScale( 16.0f );
2708 					}
2709 				}
2710 
2711 				*px2 = *px;
2712 				Sys_UpdateWindows(W_XY | W_XY_OVERLAY);
2713 			}
2714 			else {
2715 				int nDim1 = (m_nViewType == YZ) ? 1 : 0;
2716 				int nDim2 = (m_nViewType == XY) ? 1 : 2;
2717 				m_vOrigin[nDim1] -= (x - m_ptCursor.x) / m_fScale;
2718 				m_vOrigin[nDim2] += (y - m_ptCursor.y) / m_fScale;
2719 				SetCursorPos(m_ptCursor.x, m_ptCursor.y);
2720 				::ShowCursor(FALSE);
2721 
2722 				// XY_Draw(); RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
2723 				Sys_UpdateWindows(W_XY | W_XY_OVERLAY);
2724 
2725 				// ::ShowCursor(TRUE);
2726 			}
2727 		}
2728 
2729 		return false;
2730 	}
2731 
2732 	return false;
2733 }
2734 
2735 /*
2736  =======================================================================================================================
2737 	DRAWING �
2738 	XY_DrawGrid
2739  =======================================================================================================================
2740  */
XY_DrawGrid()2741 void CXYWnd::XY_DrawGrid() {
2742 	float	x, y, xb, xe, yb, ye;
2743 	int		w, h;
2744 	char	text[32];
2745 
2746 	int startPos = max ( 64 , g_qeglobals.d_gridsize );
2747 
2748 	w = m_nWidth / 2 / m_fScale;
2749 	h = m_nHeight / 2 / m_fScale;
2750 
2751 	int nDim1 = (m_nViewType == YZ) ? 1 : 0;
2752 	int nDim2 = (m_nViewType == XY) ? 1 : 2;
2753 
2754 	// int nDim1 = 0; int nDim2 = 1;
2755 	xb = m_vOrigin[nDim1] - w;
2756 	if (xb < region_mins[nDim1]) {
2757 		xb = region_mins[nDim1];
2758 	}
2759 
2760 	xb = startPos * floor(xb / startPos);
2761 
2762 	xe = m_vOrigin[nDim1] + w;
2763 	if (xe > region_maxs[nDim1]) {
2764 		xe = region_maxs[nDim1];
2765 	}
2766 
2767 	xe = startPos * ceil(xe / startPos);
2768 
2769 	yb = m_vOrigin[nDim2] - h;
2770 	if (yb < region_mins[nDim2]) {
2771 		yb = region_mins[nDim2];
2772 	}
2773 
2774 	yb = startPos * floor(yb / startPos);
2775 
2776 	ye = m_vOrigin[nDim2] + h;
2777 	if (ye > region_maxs[nDim2]) {
2778 		ye = region_maxs[nDim2];
2779 	}
2780 
2781 	ye = startPos * ceil(ye / startPos);
2782 
2783 	// draw major blocks
2784 	qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR].ToFloatPtr());
2785 
2786 	int stepSize = 64 * 0.1 / m_fScale;
2787 	if (stepSize < 64) {
2788 		stepSize = max ( 64 , g_qeglobals.d_gridsize );
2789 	}
2790 	else {
2791 		int i;
2792 		for (i = 1; i < stepSize; i <<= 1) {
2793 		}
2794 
2795 		stepSize = i;
2796 	}
2797 
2798 	if (g_qeglobals.d_showgrid) {
2799 		qglBegin(GL_LINES);
2800 
2801 		for (x = xb; x <= xe; x += stepSize) {
2802 			qglVertex2f(x, yb);
2803 			qglVertex2f(x, ye);
2804 		}
2805 
2806 		for (y = yb; y <= ye; y += stepSize) {
2807 			qglVertex2f(xb, y);
2808 			qglVertex2f(xe, y);
2809 		}
2810 
2811 		qglEnd();
2812 	}
2813 
2814 	// draw minor blocks
2815 	if ( m_fScale > .1 &&
2816 		g_qeglobals.d_showgrid &&
2817 		g_qeglobals.d_gridsize * m_fScale >= 4 &&
2818 		!g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR].Compare( g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK] ) ) {
2819 
2820 		qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR].ToFloatPtr());
2821 
2822 		qglBegin(GL_LINES);
2823 		for (x = xb; x < xe; x += g_qeglobals.d_gridsize) {
2824 			if (!((int)x & (startPos - 1))) {
2825 				continue;
2826 			}
2827 
2828 			qglVertex2f(x, yb);
2829 			qglVertex2f(x, ye);
2830 		}
2831 
2832 		for (y = yb; y < ye; y += g_qeglobals.d_gridsize) {
2833 			if (!((int)y & (startPos - 1))) {
2834 				continue;
2835 			}
2836 
2837 			qglVertex2f(xb, y);
2838 			qglVertex2f(xe, y);
2839 		}
2840 
2841 		qglEnd();
2842 	}
2843 
2844 
2845 	// draw ZClip boundaries (if applicable)...
2846 	//
2847 	if (m_nViewType == XZ || m_nViewType == YZ)
2848 	{
2849 		if (g_pParentWnd->GetZWnd()->m_pZClip)	// should always be the case at this point I think, but this is safer
2850 		{
2851 			if (g_pParentWnd->GetZWnd()->m_pZClip->IsEnabled())
2852 			{
2853 				qglColor3f(ZCLIP_COLOUR);
2854 				qglLineWidth(2);
2855 				qglBegin (GL_LINES);
2856 
2857 				qglVertex2f (xb, g_pParentWnd->GetZWnd()->m_pZClip->GetTop());
2858 				qglVertex2f (xe, g_pParentWnd->GetZWnd()->m_pZClip->GetTop());
2859 
2860 				qglVertex2f (xb, g_pParentWnd->GetZWnd()->m_pZClip->GetBottom());
2861 				qglVertex2f (xe, g_pParentWnd->GetZWnd()->m_pZClip->GetBottom());
2862 
2863 				qglEnd ();
2864 				qglLineWidth(1);
2865 			}
2866 		}
2867 	}
2868 
2869 
2870 
2871 
2872 	// draw coordinate text if needed
2873 	if (g_qeglobals.d_savedinfo.show_coordinates) {
2874 		// glColor4f(0, 0, 0, 0);
2875 		qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT].ToFloatPtr());
2876 
2877 		float	lastRaster = xb;
2878 
2879 		for (x = xb; x < xe; x += stepSize) {
2880 			qglRasterPos2f(x, m_vOrigin[nDim2] + h - 10 / m_fScale);
2881 			sprintf(text, "%i", (int)x);
2882 			qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
2883 		}
2884 
2885 		for (y = yb; y < ye; y += stepSize) {
2886 			qglRasterPos2f(m_vOrigin[nDim1] - w + 1, y);
2887 			sprintf(text, "%i", (int)y);
2888 			qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
2889 		}
2890 
2891 		if (Active()) {
2892 			qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME].ToFloatPtr());
2893 		}
2894 
2895 		qglRasterPos2f(m_vOrigin[nDim1] - w + 35 / m_fScale, m_vOrigin[nDim2] + h - 20 / m_fScale);
2896 
2897 		char	cView[20];
2898 		if (m_nViewType == XY) {
2899 			strcpy(cView, "XY Top");
2900 		}
2901 		else if (m_nViewType == XZ) {
2902 			strcpy(cView, "XZ Front");
2903 		}
2904 		else {
2905 			strcpy(cView, "YZ Side");
2906 		}
2907 
2908 		qglCallLists(strlen(cView), GL_UNSIGNED_BYTE, cView);
2909 	}
2910 
2911 	/*
2912 	 * if (true) { qglColor3f(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]);
2913 	 * qglBegin (GL_LINES); qglVertex2f (x, yb); qglVertex2f (x, ye); qglEnd(); }
2914 	 */
2915 }
2916 
2917 /*
2918  =======================================================================================================================
2919 	XY_DrawBlockGrid
2920  =======================================================================================================================
2921  */
XY_DrawBlockGrid()2922 void CXYWnd::XY_DrawBlockGrid() {
2923 	float	x, y, xb, xe, yb, ye;
2924 	int		w, h;
2925 	char	text[32];
2926 
2927 	w = m_nWidth / 2 / m_fScale;
2928 	h = m_nHeight / 2 / m_fScale;
2929 
2930 	int nDim1 = (m_nViewType == YZ) ? 1 : 0;
2931 	int nDim2 = (m_nViewType == XY) ? 1 : 2;
2932 
2933 	xb = m_vOrigin[nDim1] - w;
2934 	if (xb < region_mins[nDim1]) {
2935 		xb = region_mins[nDim1];
2936 	}
2937 
2938 	xb = 1024 * floor(xb / 1024);
2939 
2940 	xe = m_vOrigin[nDim1] + w;
2941 	if (xe > region_maxs[nDim1]) {
2942 		xe = region_maxs[nDim1];
2943 	}
2944 
2945 	xe = 1024 * ceil(xe / 1024);
2946 
2947 	yb = m_vOrigin[nDim2] - h;
2948 	if (yb < region_mins[nDim2]) {
2949 		yb = region_mins[nDim2];
2950 	}
2951 
2952 	yb = 1024 * floor(yb / 1024);
2953 
2954 	ye = m_vOrigin[nDim2] + h;
2955 	if (ye > region_maxs[nDim2]) {
2956 		ye = region_maxs[nDim2];
2957 	}
2958 
2959 	ye = 1024 * ceil(ye / 1024);
2960 
2961 	// draw major blocks
2962 	qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK].ToFloatPtr());
2963 	qglLineWidth(0.5);
2964 
2965 	qglBegin(GL_LINES);
2966 
2967 	for (x = xb; x <= xe; x += 1024) {
2968 		qglVertex2f(x, yb);
2969 		qglVertex2f(x, ye);
2970 	}
2971 
2972 	for (y = yb; y <= ye; y += 1024) {
2973 		qglVertex2f(xb, y);
2974 		qglVertex2f(xe, y);
2975 	}
2976 
2977 	qglEnd();
2978 	qglLineWidth(0.25);
2979 
2980 	// draw coordinate text if needed
2981 	for (x = xb; x < xe; x += 1024) {
2982 		for (y = yb; y < ye; y += 1024) {
2983 			qglRasterPos2f(x + 512, y + 512);
2984 			sprintf(text, "%i,%i", (int)floor(x / 1024), (int)floor(y / 1024));
2985 			qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
2986 		}
2987 	}
2988 
2989 	qglColor4f(0, 0, 0, 0);
2990 }
2991 
GLColoredBoxWithLabel(float x,float y,float size,idVec4 color,const char * text,idVec4 textColor,float xofs,float yofs,float lineSize)2992 void GLColoredBoxWithLabel(float x, float y, float size, idVec4 color, const char *text, idVec4 textColor, float xofs, float yofs, float lineSize) {
2993 	globalImages->BindNull();
2994 	qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2995 	qglDisable(GL_CULL_FACE);
2996 	qglDisable(GL_BLEND);
2997 	qglColor4f(color[0], color[1], color[2], color[3]);
2998 	qglBegin(GL_QUADS);
2999 	qglVertex3f(x - size, y - size, 0);
3000 	qglVertex3f(x + size, y - size, 0);
3001 	qglVertex3f(x + size, y + size, 0);
3002 	qglVertex3f(x - size, y + size, 0);
3003 	qglEnd();
3004 
3005 	qglColor4f(textColor[0], textColor[1], textColor[2], textColor[3]);
3006 	qglLineWidth(lineSize);
3007 	qglRasterPos2f(x + xofs, y + yofs);
3008 	qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
3009 }
3010 
3011 /*
3012  =======================================================================================================================
3013  =======================================================================================================================
3014  */
DrawRotateIcon()3015 void CXYWnd::DrawRotateIcon() {
3016 	float	x, y;
3017 
3018 	if (m_nViewType == XY) {
3019 		x = g_vRotateOrigin[0];
3020 		y = g_vRotateOrigin[1];
3021 	}
3022 	else if (m_nViewType == YZ) {
3023 		x = g_vRotateOrigin[1];
3024 		y = g_vRotateOrigin[2];
3025 	}
3026 	else {
3027 		x = g_vRotateOrigin[0];
3028 		y = g_vRotateOrigin[2];
3029 	}
3030 
3031 	qglEnable(GL_BLEND);
3032 	globalImages->BindNull();
3033 	qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
3034 	qglDisable(GL_CULL_FACE);
3035 	qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3036 	qglColor4f( 0.8f, 0.1f, 0.9f, 0.25f );
3037 
3038 	qglBegin(GL_QUADS);
3039 	qglVertex3f(x - 4, y - 4, 0);
3040 	qglVertex3f(x + 4, y - 4, 0);
3041 	qglVertex3f(x + 4, y + 4, 0);
3042 	qglVertex3f(x - 4, y + 4, 0);
3043 	qglEnd();
3044 	qglDisable(GL_BLEND);
3045 
3046 	qglColor4f( 1.0f, 0.2f, 1.0f, 1.0f );
3047 	qglBegin(GL_POINTS);
3048 	qglVertex3f(x, y, 0);
3049 	qglEnd();
3050 
3051 
3052 	int w = m_nWidth / 2 / m_fScale;
3053 	int h = m_nHeight / 2 / m_fScale;
3054 	int nDim1 = (m_nViewType == YZ) ? 1 : 0;
3055 	int nDim2 = (m_nViewType == XY) ? 1 : 2;
3056 	x = m_vOrigin[nDim1] - w + 35 / m_fScale;
3057 	y = m_vOrigin[nDim2] + h - 40 / m_fScale;
3058 	const char *p = "Rotate Z Axis";
3059 	if (g_qeglobals.rotateAxis == 1) {
3060 		p = "Rotate Y Axis";
3061 	} else if (g_qeglobals.rotateAxis == 0) {
3062 		p = "Rotate X Axis";
3063 	}
3064 	idStr str = p;
3065 	if (g_qeglobals.flatRotation) {
3066 		str += g_qeglobals.flatRotation == 2 ? " Flat [center] " : " Flat [ rot origin ] ";
3067 	}
3068 	qglRasterPos2f(x, y);
3069 	qglCallLists(str.Length(), GL_UNSIGNED_BYTE, str.c_str());
3070 }
3071 
3072 /*
3073  =======================================================================================================================
3074  =======================================================================================================================
3075  */
DrawCameraIcon()3076 void CXYWnd::DrawCameraIcon() {
3077 	float	x, y, a;
3078 
3079 	if (m_nViewType == XY) {
3080 		x = g_pParentWnd->GetCamera()->Camera().origin[0];
3081 		y = g_pParentWnd->GetCamera()->Camera().origin[1];
3082 		a = g_pParentWnd->GetCamera()->Camera().angles[YAW] * idMath::M_DEG2RAD;
3083 	}
3084 	else if (m_nViewType == YZ) {
3085 		x = g_pParentWnd->GetCamera()->Camera().origin[1];
3086 		y = g_pParentWnd->GetCamera()->Camera().origin[2];
3087 		a = g_pParentWnd->GetCamera()->Camera().angles[PITCH] * idMath::M_DEG2RAD;
3088 	}
3089 	else {
3090 		x = g_pParentWnd->GetCamera()->Camera().origin[0];
3091 		y = g_pParentWnd->GetCamera()->Camera().origin[2];
3092 		a = g_pParentWnd->GetCamera()->Camera().angles[PITCH] * idMath::M_DEG2RAD;
3093 	}
3094 
3095 	float scale = 1.0/m_fScale;	//jhefty - keep the camera icon proportionally the same size
3096 
3097 	qglColor3f(0.0, 0.0, 1.0);
3098 	qglBegin(GL_LINE_STRIP);
3099 	qglVertex3f(x - 16*scale, y, 0);
3100 	qglVertex3f(x, y + 8*scale, 0);
3101 	qglVertex3f(x + 16*scale, y, 0);
3102 	qglVertex3f(x, y - 8*scale, 0);
3103 	qglVertex3f(x - 16*scale, y, 0);
3104 	qglVertex3f(x + 16*scale, y, 0);
3105 	qglEnd();
3106 
3107 	qglBegin(GL_LINE_STRIP);
3108 	qglVertex3f(x + (48 * cos( a + idMath::PI * 0.25f )*scale), y + (48 * sin( a + idMath::PI * 0.25f )*scale), 0);
3109 	qglVertex3f(x, y, 0);
3110 	qglVertex3f(x + (48 * cos( a - idMath::PI * 0.25f )*scale), y + (48 * sin( a - idMath::PI * 0.25f )*scale), 0);
3111 	qglEnd();
3112 
3113 #if 0
3114 
3115 	char	text[128];
3116 	qglRasterPos2f(x + 64, y + 64);
3117 	sprintf(text, "%f", g_pParentWnd->GetCamera()->Camera().angles[YAW]);
3118 	qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
3119 #endif
3120 }
3121 
3122 /*
3123  =======================================================================================================================
3124  =======================================================================================================================
3125  */
DrawZIcon(void)3126 void CXYWnd::DrawZIcon(void) {
3127 	if (m_nViewType == XY) {
3128 		float	x = z.origin[0];
3129 		float	y = z.origin[1];
3130 		qglEnable(GL_BLEND);
3131 		globalImages->BindNull();
3132 		qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
3133 		qglDisable(GL_CULL_FACE);
3134 		qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3135 		qglColor4f(0.0, 0.0, 1.0, 0.25);
3136 		qglBegin(GL_QUADS);
3137 		qglVertex3f(x - 8, y - 8, 0);
3138 		qglVertex3f(x + 8, y - 8, 0);
3139 		qglVertex3f(x + 8, y + 8, 0);
3140 		qglVertex3f(x - 8, y + 8, 0);
3141 		qglEnd();
3142 		qglDisable(GL_BLEND);
3143 
3144 		qglColor4f(0.0, 0.0, 1.0, 1);
3145 
3146 		qglBegin(GL_LINE_LOOP);
3147 		qglVertex3f(x - 8, y - 8, 0);
3148 		qglVertex3f(x + 8, y - 8, 0);
3149 		qglVertex3f(x + 8, y + 8, 0);
3150 		qglVertex3f(x - 8, y + 8, 0);
3151 		qglEnd();
3152 
3153 		qglBegin(GL_LINE_STRIP);
3154 		qglVertex3f(x - 4, y + 4, 0);
3155 		qglVertex3f(x + 4, y + 4, 0);
3156 		qglVertex3f(x - 4, y - 4, 0);
3157 		qglVertex3f(x + 4, y - 4, 0);
3158 		qglEnd();
3159 	}
3160 }
3161 
3162 /*
3163  =======================================================================================================================
3164 	FilterBrush
3165  =======================================================================================================================
3166  */
FilterBrush(brush_t * pb)3167 bool FilterBrush(brush_t *pb) {
3168 
3169 	if (!pb->owner) {
3170 		return false;	// during construction
3171 	}
3172 
3173 	if (pb->hiddenBrush) {
3174 		return true;
3175 	}
3176 
3177 	if ( pb->forceVisibile ) {
3178 		return false;
3179 	}
3180 
3181 	if (g_pParentWnd->GetZWnd()->m_pZClip)	// ZClip class up and running? (and hence Z window built)
3182 	{
3183 		if (g_pParentWnd->GetZWnd()->m_pZClip->IsEnabled())
3184 		{
3185 			// ZClipping active...
3186 			//
3187 			if (pb->mins[2] > g_pParentWnd->GetZWnd()->m_pZClip->GetTop()	// brush bottom edge is above clip top
3188 				||
3189 				pb->maxs[2] < g_pParentWnd->GetZWnd()->m_pZClip->GetBottom()// brush top edge is below clip bottom
3190 				)
3191 			{
3192 				return TRUE;
3193 			}
3194 		}
3195 	}
3196 
3197 	if (g_qeglobals.d_savedinfo.exclude & (EXCLUDE_CAULK | EXCLUDE_VISPORTALS)) {
3198 		//
3199 		// filter out the brush only if all faces are caulk if not don't hide the whole
3200 		// brush, proceed on a per-face basis (Cam_Draw) ++timo TODO: set this as a
3201 		// preference .. show caulk: hide any brush with caulk // don't draw caulk faces
3202 		//
3203 		face_t	*f;
3204 		f = pb->brush_faces;
3205 		while (f) {
3206 			if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) {
3207 				if (!strstr(f->texdef.name, "caulk")) {
3208 					break;
3209 				}
3210 			} else {
3211 				if (strstr(f->texdef.name, "visportal")) {
3212 					return true;
3213 				}
3214 			}
3215 
3216 			f = f->next;
3217 		}
3218 
3219 		if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) {
3220 			if (!f) {
3221 				return true;
3222 			}
3223 		}
3224 
3225 		// ++timo FIXME: .. same deal here?
3226 		if (strstr(pb->brush_faces->texdef.name, "donotenter")) {
3227 			return true;
3228 		}
3229 	}
3230 
3231 	if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_HINT) {
3232 		if (strstr(pb->brush_faces->texdef.name, "hint")) {
3233 			return true;
3234 		}
3235 	}
3236 
3237 	if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) {
3238 		if (strstr(pb->brush_faces->texdef.name, "clip")) {
3239 			return true;
3240 		}
3241 	}
3242 
3243 	if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_TRIGGERS) {
3244 		if (strstr(pb->brush_faces->texdef.name, "trig")) {
3245 			return true;
3246 		}
3247 	}
3248 
3249 	if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_NODRAW) {
3250 		if (strstr(pb->brush_faces->texdef.name, "nodraw")) {
3251 			return true;
3252 		}
3253 	}
3254 
3255 
3256 	if (strstr(pb->brush_faces->texdef.name, "skip")) {
3257 		return true;
3258 	}
3259 
3260 	if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_DYNAMICS) {
3261 		if (pb->modelHandle > 0) {
3262 			idRenderModel *model = pb->modelHandle;
3263 			if ( dynamic_cast<idRenderModelLiquid*>(model) ) {
3264 				return true;
3265 			}
3266 		}
3267 	}
3268 
3269 	if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES) {
3270 		if (pb->pPatch) {
3271 			return true;
3272 		}
3273 	}
3274 
3275 	if (pb->owner == world_entity) {
3276 		if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) {
3277 			return true;
3278 		}
3279 
3280 		return false;
3281 	}
3282 	else {
3283 		if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT ) {
3284 			return ( idStr::Cmpn( pb->owner->eclass->name, "func_static", 10 ) != 0 );
3285 		}
3286 	}
3287 
3288 	if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS && pb->owner->eclass->nShowFlags & ECLASS_LIGHT ) {
3289 		return true;
3290 	}
3291 
3292 	if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_COMBATNODES && pb->owner->eclass->nShowFlags & ECLASS_COMBATNODE ) {
3293 		return true;
3294 	}
3295 
3296 	if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS && pb->owner->eclass->nShowFlags & ECLASS_PATH) {
3297 		return true;
3298 	}
3299 
3300 	if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_MODELS && ( pb->owner->eclass->entityModel != NULL || pb->modelHandle > 0 ) ) {
3301 		return true;
3302 	}
3303 
3304 	return false;
3305 }
3306 
3307 /*
3308  =======================================================================================================================
3309 	PATH LINES �
3310 	DrawPathLines Draws connections between entities. Needs to consider all entities, not just ones on screen, because
3311 	the lines can be visible when neither end is. Called for both camera view and xy view.
3312  =======================================================================================================================
3313  */
DrawPathLines(void)3314 void DrawPathLines(void) {
3315 	int			i, k;
3316 	idVec3		mid, mid1;
3317 	entity_t	*se, *te;
3318 	brush_t		*sb, *tb;
3319 	const char		*psz;
3320 	idVec3		dir, s1, s2;
3321 	float		len, f;
3322 	int			arrows;
3323 	int			num_entities;
3324 	const char		*ent_target[MAX_MAP_ENTITIES];
3325 	entity_t	*ent_entity[MAX_MAP_ENTITIES];
3326 
3327 	if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) {
3328 		return;
3329 	}
3330 
3331 	num_entities = 0;
3332 	for (te = entities.next; te != &entities && num_entities != MAX_MAP_ENTITIES; te = te->next) {
3333 		for (int i = 0; i < 2048; i++) {
3334 			if (i == 0) {
3335 				ent_target[num_entities] = ValueForKey(te, "target");
3336 			} else {
3337 				ent_target[num_entities] = ValueForKey(te, va("target%i", i));
3338 			}
3339 			if (ent_target[num_entities][0]) {
3340 				ent_entity[num_entities] = te;
3341 				num_entities++;
3342 			} else if (i > 16) {
3343 				break;
3344 			}
3345 		}
3346 	}
3347 
3348 	for (se = entities.next; se != &entities; se = se->next) {
3349 		psz = ValueForKey(se, "name");
3350 
3351 		if (psz == NULL || psz[0] == '\0') {
3352 			continue;
3353 		}
3354 
3355 		sb = se->brushes.onext;
3356 		if (sb == &se->brushes) {
3357 			continue;
3358 		}
3359 
3360 		for (k = 0; k < num_entities; k++) {
3361 			if (strcmp(ent_target[k], psz)) {
3362 				continue;
3363 			}
3364 
3365 			te = ent_entity[k];
3366 			tb = te->brushes.onext;
3367 			if (tb == &te->brushes) {
3368 				continue;
3369 			}
3370 
3371 			mid = sb->owner->origin;
3372 			mid1 = tb->owner->origin;
3373 
3374 			VectorSubtract(mid1, mid, dir);
3375 			len = dir.Normalize();
3376 			s1[0] = -dir[1] * 8 + dir[0] * 8;
3377 			s2[0] = dir[1] * 8 + dir[0] * 8;
3378 			s1[1] = dir[0] * 8 + dir[1] * 8;
3379 			s2[1] = -dir[0] * 8 + dir[1] * 8;
3380 
3381 			qglColor3f(se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]);
3382 
3383 			qglBegin(GL_LINES);
3384 			qglVertex3fv(mid.ToFloatPtr());
3385 			qglVertex3fv(mid1.ToFloatPtr());
3386 
3387 			arrows = (int)(len / 256) + 1;
3388 
3389 			for (i = 0; i < arrows; i++) {
3390 				f = len * (i + 0.5) / arrows;
3391 
3392 				mid1 = mid + (f * dir);
3393 
3394 				qglVertex3fv(mid1.ToFloatPtr());
3395 				qglVertex3f(mid1[0] + s1[0], mid1[1] + s1[1], mid1[2]);
3396 				qglVertex3fv(mid1.ToFloatPtr());
3397 				qglVertex3f(mid1[0] + s2[0], mid1[1] + s2[1], mid1[2]);
3398 			}
3399 
3400 			qglEnd();
3401 		}
3402 	}
3403 
3404 	return;
3405 }
3406 
3407 //
3408 // =======================================================================================================================
3409 //    can be greatly simplified but per usual i am in a hurry which is not an excuse, just a fact
3410 // =======================================================================================================================
3411 //
PaintSizeInfo(int nDim1,int nDim2,idVec3 vMinBounds,idVec3 vMaxBounds)3412 void CXYWnd::PaintSizeInfo(int nDim1, int nDim2, idVec3 vMinBounds, idVec3 vMaxBounds) {
3413 	idVec3	vSize;
3414 	VectorSubtract(vMaxBounds, vMinBounds, vSize);
3415 
3416 	qglColor3f
3417 	(
3418 		g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] * .65,
3419 		g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] * .65,
3420 		g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] * .65
3421 	);
3422 
3423 	if (m_nViewType == XY) {
3424 		qglBegin(GL_LINES);
3425 
3426 		qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f);
3427 		qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
3428 
3429 		qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
3430 		qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
3431 
3432 		qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f);
3433 		qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
3434 
3435 		qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2], 0.0f);
3436 		qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f);
3437 
3438 		qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f);
3439 		qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f);
3440 
3441 		qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2], 0.0f);
3442 		qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f);
3443 
3444 		qglEnd();
3445 
3446 		qglRasterPos3f(Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale, 0.0f);
3447 		g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
3448 		qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3449 
3450 		qglRasterPos3f(vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]), 0.0f);
3451 		g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
3452 		qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3453 
3454 		qglRasterPos3f(vMinBounds[nDim1] + 4, vMaxBounds[nDim2] + 8 / m_fScale, 0.0f);
3455 		g_strDim.Format(g_pOrgStrings[0], vMinBounds[nDim1], vMaxBounds[nDim2]);
3456 		qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3457 	}
3458 	else if (m_nViewType == XZ) {
3459 		qglBegin(GL_LINES);
3460 
3461 		qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f / m_fScale);
3462 		qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
3463 
3464 		qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
3465 		qglVertex3f(vMaxBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
3466 
3467 		qglVertex3f(vMaxBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f / m_fScale);
3468 		qglVertex3f(vMaxBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
3469 
3470 		qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0, vMinBounds[nDim2]);
3471 		qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMinBounds[nDim2]);
3472 
3473 		qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMinBounds[nDim2]);
3474 		qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMaxBounds[nDim2]);
3475 
3476 		qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0, vMaxBounds[nDim2]);
3477 		qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMaxBounds[nDim2]);
3478 
3479 		qglEnd();
3480 
3481 		qglRasterPos3f(Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), 0, vMinBounds[nDim2] - 20.0 / m_fScale);
3482 		g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
3483 		qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3484 
3485 		qglRasterPos3f(vMaxBounds[nDim1] + 16.0 / m_fScale, 0, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]));
3486 		g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
3487 		qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3488 
3489 		qglRasterPos3f(vMinBounds[nDim1] + 4, 0, vMaxBounds[nDim2] + 8 / m_fScale);
3490 		g_strDim.Format(g_pOrgStrings[1], vMinBounds[nDim1], vMaxBounds[nDim2]);
3491 		qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3492 	}
3493 	else {
3494 		qglBegin(GL_LINES);
3495 
3496 		qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale);
3497 		qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
3498 
3499 		qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
3500 		qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
3501 
3502 		qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale);
3503 		qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
3504 
3505 		qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2]);
3506 		qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]);
3507 
3508 		qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]);
3509 		qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]);
3510 
3511 		qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2]);
3512 		qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]);
3513 
3514 		qglEnd();
3515 
3516 		qglRasterPos3f(0, Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale);
3517 		g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
3518 		qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3519 
3520 		qglRasterPos3f(0, vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]));
3521 		g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
3522 		qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3523 
3524 		qglRasterPos3f(0, vMinBounds[nDim1] + 4.0, vMaxBounds[nDim2] + 8 / m_fScale);
3525 		g_strDim.Format(g_pOrgStrings[2], vMinBounds[nDim1], vMaxBounds[nDim2]);
3526 		qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3527 	}
3528 }
3529 
3530 /* XY_Draw */
3531 long		g_lCount = 0;
3532 long		g_lTotal = 0;
3533 extern void DrawBrushEntityName(brush_t *b);
3534 
3535 /*
3536  =======================================================================================================================
3537  =======================================================================================================================
3538  */
XY_Draw()3539 void CXYWnd::XY_Draw() {
3540 	brush_t		*brush;
3541 	float		w, h;
3542 	entity_t	*e;
3543 	idVec3		mins, maxs;
3544 	int			drawn, culled;
3545 	int			i;
3546 
3547 	if (!active_brushes.next) {
3548 		return; // not valid yet
3549 	}
3550 
3551 	// clear
3552 	m_bDirty = false;
3553 
3554 	GL_State( GLS_DEFAULT );
3555 	qglViewport(0, 0, m_nWidth, m_nHeight);
3556 	qglScissor(0, 0, m_nWidth, m_nHeight);
3557 	qglClearColor
3558 	(
3559 		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0],
3560 		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1],
3561 		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],
3562 		0
3563 	);
3564 
3565 	qglDisable(GL_DEPTH_TEST);
3566 	qglDisable(GL_CULL_FACE);
3567 	qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3568 
3569 	// set up viewpoint
3570 	qglMatrixMode(GL_PROJECTION);
3571 	qglLoadIdentity();
3572 
3573 	w = m_nWidth / 2 / m_fScale;
3574 	h = m_nHeight / 2 / m_fScale;
3575 
3576 	int nDim1 = (m_nViewType == YZ) ? 1 : 0;
3577 	int nDim2 = (m_nViewType == XY) ? 1 : 2;
3578 	mins[0] = m_vOrigin[nDim1] - w;
3579 	maxs[0] = m_vOrigin[nDim1] + w;
3580 	mins[1] = m_vOrigin[nDim2] - h;
3581 	maxs[1] = m_vOrigin[nDim2] + h;
3582 
3583 	idBounds viewBounds( mins, maxs );
3584 	viewBounds[0].z = -99999;
3585 	viewBounds[1].z = 99999;
3586 
3587 	qglOrtho(mins[0], maxs[0], mins[1], maxs[1], MIN_WORLD_COORD, MAX_WORLD_COORD);
3588 
3589 	// draw stuff
3590 	globalImages->BindNull();
3591 	// now draw the grid
3592 	qglLineWidth(0.25);
3593 	XY_DrawGrid();
3594 	qglLineWidth(0.5);
3595 
3596 	drawn = culled = 0;
3597 
3598 	if (m_nViewType != XY) {
3599 		qglPushMatrix();
3600 		if (m_nViewType == YZ) {
3601 			qglRotatef(-90, 0, 1, 0);	// put Z going up
3602 		}
3603 
3604 		// else
3605 		qglRotatef(-90, 1, 0, 0);		// put Z going up
3606 	}
3607 
3608 	e = world_entity;
3609 
3610 	for ( brush = active_brushes.next; brush != &active_brushes; brush = brush->next ) {
3611 		if ( brush->forceVisibile || ( brush->owner->eclass->nShowFlags & ( ECLASS_LIGHT | ECLASS_PROJECTEDLIGHT ) ) ) {
3612 		} else if (	brush->mins[nDim1] > maxs[0] ||	brush->mins[nDim2] > maxs[1] ||	brush->maxs[nDim1] < mins[0] || brush->maxs[nDim2] < mins[1] ) {
3613 			culled++;
3614 			continue;				// off screen
3615 		}
3616 
3617 		if ( FilterBrush(brush) ) {
3618 			continue;
3619 		}
3620 
3621 		drawn++;
3622 
3623 		if (brush->owner != e && brush->owner) {
3624 			qglColor3fv(brush->owner->eclass->color.ToFloatPtr());
3625 		}
3626 		else {
3627 			qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES].ToFloatPtr());
3628 		}
3629 
3630 		Brush_DrawXY( brush, m_nViewType );
3631 	}
3632 
3633 	DrawPathLines();
3634 
3635 	// draw pointfile
3636 	if (g_qeglobals.d_pointfile_display_list) {
3637 		qglCallList(g_qeglobals.d_pointfile_display_list);
3638 	}
3639 
3640 	if (!(m_nViewType == XY)) {
3641 		qglPopMatrix();
3642 	}
3643 
3644 	// draw block grid
3645 	if (g_qeglobals.show_blocks) {
3646 		XY_DrawBlockGrid();
3647 	}
3648 
3649 	// now draw selected brushes
3650 	if (m_nViewType != XY) {
3651 		qglPushMatrix();
3652 		if (m_nViewType == YZ) {
3653 			qglRotatef(-90, 0, 1, 0);	// put Z going up
3654 		}
3655 
3656 		// else
3657 		qglRotatef(-90, 1, 0, 0);		// put Z going up
3658 	}
3659 
3660 	qglPushMatrix();
3661 	qglTranslatef
3662 	(
3663 		g_qeglobals.d_select_translate[0],
3664 		g_qeglobals.d_select_translate[1],
3665 		g_qeglobals.d_select_translate[2]
3666 	);
3667 
3668 	if (RotateMode()) {
3669 		qglColor3f( 0.8f, 0.1f, 0.9f );
3670 	}
3671 	else if (ScaleMode()) {
3672 		qglColor3f( 0.1f, 0.8f, 0.1f );
3673 	}
3674 	else {
3675 		qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr());
3676 	}
3677 
3678 	if (g_PrefsDlg.m_bNoStipple == FALSE) {
3679 		qglEnable(GL_LINE_STIPPLE);
3680 		qglLineStipple(3, 0xaaaa);
3681 	}
3682 
3683 	qglLineWidth(1);
3684 
3685 	idVec3	vMinBounds;
3686 	idVec3	vMaxBounds;
3687 	vMinBounds[0] = vMinBounds[1] = vMinBounds[2] = 999999.9f;
3688 	vMaxBounds[0] = vMaxBounds[1] = vMaxBounds[2] = -999999.9f;
3689 
3690 	int		nSaveDrawn = drawn;
3691 	bool	bFixedSize = false;
3692 	for (brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next) {
3693 		drawn++;
3694 		Brush_DrawXY(brush, m_nViewType, true);
3695 
3696 		if (!bFixedSize) {
3697 			if (brush->owner->eclass->fixedsize) {
3698 				bFixedSize = true;
3699 			}
3700 
3701 			if (g_PrefsDlg.m_bSizePaint) {
3702 				for (i = 0; i < 3; i++) {
3703 					if (brush->mins[i] < vMinBounds[i]) {
3704 						vMinBounds[i] = brush->mins[i];
3705 					}
3706 
3707 					if (brush->maxs[i] > vMaxBounds[i]) {
3708 						vMaxBounds[i] = brush->maxs[i];
3709 					}
3710 				}
3711 			}
3712 		}
3713 	}
3714 
3715 	if (g_PrefsDlg.m_bNoStipple == FALSE) {
3716 		qglDisable(GL_LINE_STIPPLE);
3717 	}
3718 
3719 	qglLineWidth(0.5);
3720 
3721 	if (!bFixedSize && !RotateMode() && !ScaleMode() && drawn - nSaveDrawn > 0 && g_PrefsDlg.m_bSizePaint) {
3722 		PaintSizeInfo(nDim1, nDim2, vMinBounds, vMaxBounds);
3723 	}
3724 
3725 	// edge / vertex flags
3726 	if (g_qeglobals.d_select_mode == sel_vertex) {
3727 		qglPointSize(4);
3728 		qglColor3f(0, 1, 0);
3729 		qglBegin(GL_POINTS);
3730 		for (i = 0; i < g_qeglobals.d_numpoints; i++) {
3731 			qglVertex3fv(g_qeglobals.d_points[i].ToFloatPtr());
3732 		}
3733 
3734 		qglEnd();
3735 		qglPointSize(1);
3736 	}
3737 	else if (g_qeglobals.d_select_mode == sel_edge) {
3738 		float	*v1, *v2;
3739 
3740 		qglPointSize(4);
3741 		qglColor3f(0, 0, 1);
3742 		qglBegin(GL_POINTS);
3743 		for (i = 0; i < g_qeglobals.d_numedges; i++) {
3744 			v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1].ToFloatPtr();
3745 			v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2].ToFloatPtr();
3746 			qglVertex3f((v1[0] + v2[0]) * 0.5, (v1[1] + v2[1]) * 0.5, (v1[2] + v2[2]) * 0.5);
3747 		}
3748 
3749 		qglEnd();
3750 		qglPointSize(1);
3751 	}
3752 
3753 	g_splineList->draw (static_cast<bool>(g_qeglobals.d_select_mode == sel_editpoint || g_qeglobals.d_select_mode == sel_addpoint));
3754 
3755 	if (g_pParentWnd->GetNurbMode() && g_pParentWnd->GetNurb()->GetNumValues()) {
3756 		int maxage = g_pParentWnd->GetNurb()->GetNumValues();
3757 		int time = 0;
3758 		qglColor3f(0, 0, 1);
3759 		qglPointSize(1);
3760 		qglBegin(GL_POINTS);
3761 		g_pParentWnd->GetNurb()->SetOrder(3);
3762 		for (i = 0; i < 100; i++) {
3763 			idVec2 v = g_pParentWnd->GetNurb()->GetCurrentValue(time);
3764 			qglVertex3f(v.x, v.y, 0.0f);
3765 			time += 10;
3766 		}
3767 		qglEnd();
3768 		qglPointSize(4);
3769 		qglColor3f(0, 0, 1);
3770 		qglBegin(GL_POINTS);
3771 		for (i = 0; i < maxage; i++) {
3772 			idVec2 v = g_pParentWnd->GetNurb()->GetValue(i);
3773 			qglVertex3f(v.x, v.y, 0.0f);
3774 		}
3775 		qglEnd();
3776 		qglPointSize(1);
3777 	}
3778 
3779 	qglPopMatrix();
3780 
3781 	qglTranslatef
3782 	(
3783 		-g_qeglobals.d_select_translate[0],
3784 		-g_qeglobals.d_select_translate[1],
3785 		-g_qeglobals.d_select_translate[2]
3786 	);
3787 
3788 	if (!(m_nViewType == XY)) {
3789 		qglPopMatrix();
3790 	}
3791 
3792 	// area selection hack
3793 	if (g_qeglobals.d_select_mode == sel_area) {
3794 		qglEnable(GL_BLEND);
3795 		qglPolygonMode ( GL_FRONT_AND_BACK , GL_FILL );
3796 		qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3797 		qglColor4f(0.0, 0.0, 1.0, 0.25);
3798 		qglRectf
3799 		(
3800 			g_qeglobals.d_vAreaTL[nDim1],
3801 			g_qeglobals.d_vAreaTL[nDim2],
3802 			g_qeglobals.d_vAreaBR[nDim1],
3803 			g_qeglobals.d_vAreaBR[nDim2]
3804 		);
3805 		qglDisable(GL_BLEND);
3806 		qglPolygonMode ( GL_FRONT_AND_BACK , GL_LINE );
3807 		qglColor3f(1.0f, 1.0f, 1.0f);
3808 		qglRectf
3809 		(
3810 			g_qeglobals.d_vAreaTL[nDim1],
3811 			g_qeglobals.d_vAreaTL[nDim2],
3812 			g_qeglobals.d_vAreaBR[nDim1],
3813 			g_qeglobals.d_vAreaBR[nDim2]
3814 		);
3815 
3816 	}
3817 
3818 	// now draw camera point
3819 	DrawCameraIcon();
3820 	DrawZIcon();
3821 
3822 	if (RotateMode()) {
3823 		DrawRotateIcon();
3824 	}
3825 
3826 	/// Draw a "precision crosshair" if enabled
3827 	if( m_precisionCrosshairMode != PRECISION_CROSSHAIR_NONE )
3828 		DrawPrecisionCrosshair();
3829 
3830 	qglFlush();
3831 
3832 	// QE_CheckOpenGLForErrors();
3833 }
3834 
3835 
3836 /*
3837  =======================================================================================================================
3838  =======================================================================================================================
3839  */
GetOrigin()3840 idVec3 &CXYWnd::GetOrigin() {
3841 	return m_vOrigin;
3842 }
3843 
3844 /*
3845  =======================================================================================================================
3846  =======================================================================================================================
3847  */
SetOrigin(idVec3 org)3848 void CXYWnd::SetOrigin(idVec3 org) {
3849 	m_vOrigin[0] = org[0];
3850 	m_vOrigin[1] = org[1];
3851 	m_vOrigin[2] = org[2];
3852 }
3853 
3854 /*
3855  =======================================================================================================================
3856  =======================================================================================================================
3857  */
OnSize(UINT nType,int cx,int cy)3858 void CXYWnd::OnSize(UINT nType, int cx, int cy) {
3859 	CWnd::OnSize(nType, cx, cy);
3860 
3861 	CRect	rect;
3862 	GetClientRect(rect);
3863 	m_nWidth = rect.Width();
3864 	m_nHeight = rect.Height();
3865 	InvalidateRect(NULL, false);
3866 }
3867 
3868 brush_t hold_brushes;
3869 
3870 /*
3871  =======================================================================================================================
3872  =======================================================================================================================
3873  */
Clip()3874 void CXYWnd::Clip() {
3875 	if (ClipMode()) {
3876 		hold_brushes.next = &hold_brushes;
3877 		ProduceSplitLists();
3878 
3879 		// brush_t* pList = (g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
3880 		brush_t *pList;
3881 		if (g_PrefsDlg.m_bSwitchClip) {
3882 			pList = ((m_nViewType == XZ) ? g_bSwitch : !g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
3883 		}
3884 		else {
3885 			pList = ((m_nViewType == XZ) ? !g_bSwitch : g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
3886 		}
3887 
3888 		if (pList->next != pList) {
3889 			Brush_CopyList(pList, &hold_brushes);
3890 			CleanList(&g_brFrontSplits);
3891 			CleanList(&g_brBackSplits);
3892 			Select_Delete();
3893 			Brush_CopyList(&hold_brushes, &selected_brushes);
3894 			if (RogueClipMode()) {
3895 				RetainClipMode(false);
3896 			}
3897 			else {
3898 				RetainClipMode(true);
3899 			}
3900 
3901 			Sys_UpdateWindows(W_ALL);
3902 		}
3903 	}
3904 	else if (PathMode()) {
3905 		FinishSmartCreation();
3906 		if (g_pPathFunc) {
3907 			g_pPathFunc(true, g_nPathCount);
3908 		}
3909 
3910 		g_pPathFunc = NULL;
3911 		g_nPathCount = 0;
3912 		g_bPathMode = false;
3913 	}
3914 }
3915 
3916 /*
3917  =======================================================================================================================
3918  =======================================================================================================================
3919  */
SplitClip()3920 void CXYWnd::SplitClip() {
3921 	ProduceSplitLists();
3922 	if ((g_brFrontSplits.next != &g_brFrontSplits) && (g_brBackSplits.next != &g_brBackSplits)) {
3923 		Select_Delete();
3924 		Brush_CopyList(&g_brFrontSplits, &selected_brushes);
3925 		Brush_CopyList(&g_brBackSplits, &selected_brushes);
3926 		CleanList(&g_brFrontSplits);
3927 		CleanList(&g_brBackSplits);
3928 		if (RogueClipMode()) {
3929 			RetainClipMode(false);
3930 		}
3931 		else {
3932 			RetainClipMode(true);
3933 		}
3934 	}
3935 }
3936 
3937 /*
3938  =======================================================================================================================
3939  =======================================================================================================================
3940  */
FlipClip()3941 void CXYWnd::FlipClip() {
3942 	g_bSwitch = !g_bSwitch;
3943 	Sys_UpdateWindows(XY | W_CAMERA_IFON);
3944 }
3945 
3946 //
3947 // =======================================================================================================================
3948 //    makes sure the selected brush or camera is in view
3949 // =======================================================================================================================
3950 //
PositionView()3951 void CXYWnd::PositionView() {
3952 	int		nDim1 = (m_nViewType == YZ) ? 1 : 0;
3953 	int		nDim2 = (m_nViewType == XY) ? 1 : 2;
3954 	brush_t *b = selected_brushes.next;
3955 	if (b && b->next != b) {
3956 		m_vOrigin[nDim1] = b->mins[nDim1];
3957 		m_vOrigin[nDim2] = b->mins[nDim2];
3958 	}
3959 	else {
3960 		m_vOrigin[nDim1] = g_pParentWnd->GetCamera()->Camera().origin[nDim1];
3961 		m_vOrigin[nDim2] = g_pParentWnd->GetCamera()->Camera().origin[nDim2];
3962 	}
3963 }
3964 
3965 /*
3966  =======================================================================================================================
3967  =======================================================================================================================
3968  */
VectorCopyXY(const idVec3 & in,idVec3 & out)3969 void CXYWnd::VectorCopyXY(const idVec3 &in, idVec3 &out) {
3970 	if (m_nViewType == XY) {
3971 		out[0] = in[0];
3972 		out[1] = in[1];
3973 	}
3974 	else if (m_nViewType == XZ) {
3975 		out[0] = in[0];
3976 		out[2] = in[2];
3977 	}
3978 	else {
3979 		out[1] = in[1];
3980 		out[2] = in[2];
3981 	}
3982 }
3983 
3984 /*
3985  =======================================================================================================================
3986  =======================================================================================================================
3987  */
OnDestroy()3988 void CXYWnd::OnDestroy() {
3989 	CWnd::OnDestroy();
3990 
3991 	// delete this;
3992 }
3993 
3994 /*
3995  =======================================================================================================================
3996  =======================================================================================================================
3997  */
SetViewType(int n)3998 void CXYWnd::SetViewType(int n) {
3999 	m_nViewType = n;
4000 	char *p = "YZ Side";
4001 	if (m_nViewType == XY) {
4002 		p = "XY Top";
4003 	} else if (m_nViewType == XZ) {
4004 		p = "XZ Front";
4005 	}
4006 	SetWindowText(p);
4007 };
4008 
4009 /*
4010  =======================================================================================================================
4011  =======================================================================================================================
4012  */
Redraw(unsigned int nBits)4013 void CXYWnd::Redraw(unsigned int nBits) {
4014 	m_nUpdateBits = nBits;
4015 	RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
4016 	m_nUpdateBits = W_XY;
4017 }
4018 
4019 /*
4020  =======================================================================================================================
4021  =======================================================================================================================
4022  */
RotateMode()4023 bool CXYWnd::RotateMode() {
4024 	return g_bRotateMode;
4025 }
4026 
4027 /*
4028  =======================================================================================================================
4029  =======================================================================================================================
4030  */
ScaleMode()4031 bool CXYWnd::ScaleMode() {
4032 	return g_bScaleMode;
4033 }
4034 
4035 /*
4036  =======================================================================================================================
4037  =======================================================================================================================
4038  */
4039 extern bool Select_OnlyModelsSelected();
SetRotateMode(bool bMode)4040 bool CXYWnd::SetRotateMode(bool bMode) {
4041 	if (bMode && selected_brushes.next != &selected_brushes) {
4042 		g_bRotateMode = true;
4043 		if (Select_OnlyModelsSelected()) {
4044 			Select_GetTrueMid(g_vRotateOrigin);
4045 		} else {
4046 			Select_GetMid(g_vRotateOrigin);
4047 		}
4048 		g_vRotation.Zero();
4049 		Select_InitializeRotation();
4050 	}
4051 	else {
4052 		if (bMode) {
4053 			Sys_Status("Need a brush selected to turn on Mouse Rotation mode\n");
4054 		}
4055 
4056 		g_bRotateMode = false;
4057 		Select_FinalizeRotation();
4058 	}
4059 
4060 	RedrawWindow();
4061 	return g_bRotateMode;
4062 }
4063 
4064 /*
4065  =======================================================================================================================
4066  =======================================================================================================================
4067  */
SetScaleMode(bool bMode)4068 void CXYWnd::SetScaleMode(bool bMode) {
4069 	g_bScaleMode = bMode;
4070 	RedrawWindow();
4071 }
4072 
4073 //
4074 // =======================================================================================================================
4075 //    xy - z xz - y yz - x
4076 // =======================================================================================================================
4077 //
OnSelectMouserotate()4078 void CXYWnd::OnSelectMouserotate() {
4079 	// TODO: Add your command handler code here
4080 }
4081 
4082 /*
4083  =======================================================================================================================
4084  =======================================================================================================================
4085  */
CleanCopyEntities()4086 void CleanCopyEntities() {
4087 	entity_t	*pe = g_enClipboard.next;
4088 	while (pe != NULL && pe != &g_enClipboard) {
4089 		entity_t	*next = pe->next;
4090 		pe->epairs.Clear();
4091 
4092 		Entity_Free(pe);
4093 		pe = next;
4094 	}
4095 
4096 	g_enClipboard.next = g_enClipboard.prev = &g_enClipboard;
4097 }
4098 
4099 /*
4100  =======================================================================================================================
4101  =======================================================================================================================
4102  */
Entity_CopyClone(entity_t * e)4103 entity_t *Entity_CopyClone(entity_t *e) {
4104 	entity_t	*n;
4105 
4106 	n = Entity_New();
4107 	n->brushes.onext = n->brushes.oprev = &n->brushes;
4108 	n->eclass = e->eclass;
4109 	n->rotation = e->rotation;
4110 
4111 	// add the entity to the entity list
4112 	n->next = g_enClipboard.next;
4113 	g_enClipboard.next = n;
4114 	n->next->prev = n;
4115 	n->prev = &g_enClipboard;
4116 
4117 	n->epairs = e->epairs;
4118 
4119 	return n;
4120 }
4121 
4122 /*
4123  =======================================================================================================================
4124  =======================================================================================================================
4125  */
OnList(entity_t * pFind,CPtrArray * pList)4126 bool OnList(entity_t *pFind, CPtrArray *pList) {
4127 	int nSize = pList->GetSize();
4128 	while (nSize-- > 0) {
4129 		entity_t	*pEntity = reinterpret_cast < entity_t * > (pList->GetAt(nSize));
4130 		if (pEntity == pFind) {
4131 			return true;
4132 		}
4133 	}
4134 
4135 	return false;
4136 }
4137 
4138 /*
4139  =======================================================================================================================
4140  =======================================================================================================================
4141  */
Copy()4142 void CXYWnd::Copy()
4143 {
4144 #if 1
4145 	CWaitCursor WaitCursor;
4146 	g_Clipboard.SetLength(0);
4147 	g_PatchClipboard.SetLength(0);
4148 
4149 	Map_SaveSelected(&g_Clipboard, &g_PatchClipboard);
4150 
4151 	bool	bClipped = false;
4152 	UINT	nClipboard = ::RegisterClipboardFormat("RadiantClippings");
4153 	if (nClipboard > 0) {
4154 		if (OpenClipboard()) {
4155 			::EmptyClipboard();
4156 
4157 			long	lSize = g_Clipboard.GetLength();
4158 			HANDLE	h = ::GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, lSize + sizeof (long));
4159 			if (h != NULL) {
4160 				unsigned char	*cp = reinterpret_cast < unsigned char * > (::GlobalLock(h));
4161 				memcpy(cp, &lSize, sizeof (long));
4162 				cp += sizeof (long);
4163 				g_Clipboard.SeekToBegin();
4164 				g_Clipboard.Read(cp, lSize);
4165 				::GlobalUnlock(h);
4166 				::SetClipboardData(nClipboard, h);
4167 				::CloseClipboard();
4168 				bClipped = true;
4169 			}
4170 		}
4171 	}
4172 
4173 	if (!bClipped) {
4174 		common->Printf("Unable to register Windows clipboard formats, copy/paste between editors will not be possible");
4175 	}
4176 
4177 	/*
4178 	 * CString strOut; ::GetTempPath(1024, strOut.GetBuffer(1024));
4179 	 * strOut.ReleaseBuffer(); AddSlash(strOut); strOut += "RadiantClipboard.$$$";
4180 	 * Map_SaveSelected(strOut.GetBuffer(0));
4181 	 */
4182 #else
4183 	CPtrArray	holdArray;
4184 	CleanList(&g_brClipboard);
4185 	CleanCopyEntities();
4186 	for (brush_t * pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) {
4187 		if (pBrush->owner == world_entity) {
4188 			brush_t *pClone = Brush_Clone(pBrush);
4189 			pClone->owner = NULL;
4190 			Brush_AddToList(pClone, &g_brClipboard);
4191 		}
4192 		else {
4193 			if (!OnList(pBrush->owner, &holdArray)) {
4194 				entity_t	*e = pBrush->owner;
4195 				holdArray.Add(reinterpret_cast < void * > (e));
4196 
4197 				entity_t	*pEClone = Entity_CopyClone(e);
4198 				for (brush_t * pEB = e->brushes.onext; pEB != &e->brushes; pEB = pEB->onext) {
4199 					brush_t *pClone = Brush_Clone(pEB);
4200 
4201 					// Brush_AddToList (pClone, &g_brClipboard);
4202 					Entity_LinkBrush(pEClone, pClone);
4203 					Brush_Build(pClone);
4204 				}
4205 			}
4206 		}
4207 	}
4208 #endif
4209 }
4210 
4211 /*
4212  =======================================================================================================================
4213  =======================================================================================================================
4214  */
Undo()4215 void CXYWnd::Undo() {
4216 	/*
4217 	 * if (g_brUndo.next != &g_brUndo) { g_bScreenUpdates = false; Select_Delete();
4218 	 * for (brush_t* pBrush = g_brUndo.next ; pBrush != NULL && pBrush != &g_brUndo ;
4219 	 * pBrush=pBrush->next) { brush_t* pClone = Brush_Clone(pBrush); Brush_AddToList
4220 	 * (pClone, &active_brushes); Entity_LinkBrush (pBrush->pUndoOwner, pClone);
4221 	 * Brush_Build(pClone); Select_Brush(pClone); } CleanList(&g_brUndo);
4222 	 * g_bScreenUpdates = true; Sys_UpdateWindows(W_ALL); } else common->Printf("Nothing
4223 	 * to undo.../n");
4224 	 */
4225 }
4226 
4227 /*
4228  =======================================================================================================================
4229  =======================================================================================================================
4230  */
UndoClear()4231 void CXYWnd::UndoClear() {
4232 	/* CleanList(&g_brUndo); */
4233 }
4234 
4235 /*
4236  =======================================================================================================================
4237  =======================================================================================================================
4238  */
UndoCopy()4239 void CXYWnd::UndoCopy() {
4240 	/*
4241 	 * CleanList(&g_brUndo); for (brush_t* pBrush = selected_brushes.next ; pBrush !=
4242 	 * NULL && pBrush != &selected_brushes ; pBrush=pBrush->next) { brush_t* pClone =
4243 	 * Brush_Clone(pBrush); pClone->pUndoOwner = pBrush->owner; Brush_AddToList
4244 	 * (pClone, &g_brUndo); }
4245 	 */
4246 }
4247 
4248 /*
4249  =======================================================================================================================
4250  =======================================================================================================================
4251  */
UndoAvailable()4252 bool CXYWnd::UndoAvailable() {
4253 	return(g_brUndo.next != &g_brUndo);
4254 }
4255 
4256 /*
4257  =======================================================================================================================
4258  =======================================================================================================================
4259  */
Paste()4260 void CXYWnd::Paste()
4261 {
4262 #if 1
4263 
4264 	CWaitCursor WaitCursor;
4265 	bool		bPasted = false;
4266 	UINT		nClipboard = ::RegisterClipboardFormat("RadiantClippings");
4267 	if (nClipboard > 0 && OpenClipboard() && ::IsClipboardFormatAvailable(nClipboard)) {
4268 		HANDLE	h = ::GetClipboardData(nClipboard);
4269 		if (h) {
4270 			g_Clipboard.SetLength(0);
4271 
4272 			unsigned char	*cp = reinterpret_cast < unsigned char * > (::GlobalLock(h));
4273 			long			lSize = 0;
4274 			memcpy(&lSize, cp, sizeof (long));
4275 			cp += sizeof (long);
4276 			g_Clipboard.Write(cp, lSize);
4277 		}
4278 
4279 		::GlobalUnlock(h);
4280 		::CloseClipboard();
4281 	}
4282 
4283 	if (g_Clipboard.GetLength() > 0) {
4284 		g_Clipboard.SeekToBegin();
4285 
4286 		int		nLen = g_Clipboard.GetLength();
4287 		char	*pBuffer = new char[nLen + 1];
4288 		memset(pBuffer, 0, sizeof(*pBuffer) * (nLen + 1));
4289 		g_Clipboard.Read(pBuffer, nLen);
4290 		pBuffer[nLen] = '\0';
4291 		Map_ImportBuffer(pBuffer, !(GetAsyncKeyState(VK_SHIFT) & 0x8000));
4292 		delete[] pBuffer;
4293 	}
4294 
4295 	#if 0
4296 	if (g_PatchClipboard.GetLength() > 0) {
4297 		g_PatchClipboard.SeekToBegin();
4298 
4299 		int		nLen = g_PatchClipboard.GetLength();
4300 		char	*pBuffer = new char[nLen + 1];
4301 		g_PatchClipboard.Read(pBuffer, nLen);
4302 		pBuffer[nLen] = '\0';
4303 		Patch_ReadBuffer(pBuffer, true);
4304 		delete[] pBuffer;
4305 	}
4306 	#endif
4307 #else
4308 	if (g_brClipboard.next != &g_brClipboard || g_enClipboard.next != &g_enClipboard) {
4309 		Select_Deselect();
4310 
4311 		for (brush_t * pBrush = g_brClipboard.next; pBrush != NULL && pBrush != &g_brClipboard; pBrush = pBrush->next) {
4312 			brush_t *pClone = Brush_Clone(pBrush);
4313 
4314 			// pClone->owner = pBrush->owner;
4315 			if (pClone->owner == NULL) {
4316 				Entity_LinkBrush(world_entity, pClone);
4317 			}
4318 
4319 			Brush_AddToList(pClone, &selected_brushes);
4320 			Brush_Build(pClone);
4321 		}
4322 
4323 		for
4324 		(
4325 			entity_t * pEntity = g_enClipboard.next;
4326 			pEntity != NULL && pEntity != &g_enClipboard;
4327 			pEntity = pEntity->next
4328 		) {
4329 			entity_t	*pEClone = Entity_Clone(pEntity);
4330 			for (brush_t * pEB = pEntity->brushes.onext; pEB != &pEntity->brushes; pEB = pEB->onext) {
4331 				brush_t *pClone = Brush_Clone(pEB);
4332 				Brush_AddToList(pClone, &selected_brushes);
4333 				Entity_LinkBrush(pEClone, pClone);
4334 				Brush_Build(pClone);
4335 				if (pClone->owner && pClone->owner != world_entity) {
4336 					g_Inspectors->UpdateEntitySel(pClone->owner->eclass);
4337 				}
4338 			}
4339 		}
4340 
4341 		Sys_UpdateWindows(W_ALL);
4342 	}
4343 	else {
4344 		common->Printf("Nothing to paste.../n");
4345 	}
4346 #endif
4347 }
4348 
4349 /*
4350  =======================================================================================================================
4351  =======================================================================================================================
4352  */
Rotation()4353 idVec3 &CXYWnd::Rotation() {
4354 	return g_vRotation;
4355 }
4356 
4357 /*
4358  =======================================================================================================================
4359  =======================================================================================================================
4360  */
RotateOrigin()4361 idVec3 &CXYWnd::RotateOrigin() {
4362 	return g_vRotateOrigin;
4363 }
4364 
4365 /*
4366  =======================================================================================================================
4367  =======================================================================================================================
4368  */
OnTimer(UINT nIDEvent)4369 void CXYWnd::OnTimer(UINT nIDEvent) {
4370 	if (nIDEvent == 100) {
4371 		int nDim1 = (m_nViewType == YZ) ? 1 : 0;
4372 		int nDim2 = (m_nViewType == XY) ? 1 : 2;
4373 		m_vOrigin[nDim1] += m_ptDragAdj.x / m_fScale;
4374 		m_vOrigin[nDim2] -= m_ptDragAdj.y / m_fScale;
4375 		Sys_UpdateWindows(W_XY | W_CAMERA);
4376 
4377 		// int nH = (m_ptDrag.y == 0) ? -1 : m_ptDrag.y;
4378 		m_ptDrag += m_ptDragAdj;
4379 		m_ptDragTotal += m_ptDragAdj;
4380 		XY_MouseMoved(m_ptDrag.x, m_nHeight - 1 - m_ptDrag.y, m_nScrollFlags);
4381 
4382 		//
4383 		// m_vOrigin[nDim1] -= m_ptDrag.x / m_fScale; m_vOrigin[nDim1] -= m_ptDrag.x /
4384 		// m_fScale;
4385 		//
4386 	}
4387 }
4388 
4389 /*
4390  =======================================================================================================================
4391  =======================================================================================================================
4392  */
OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)4393 void CXYWnd::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) {
4394 	g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags, false);
4395 
4396 	// CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
4397 }
4398 
4399 /*
4400  =======================================================================================================================
4401  =======================================================================================================================
4402  */
OnNcCalcSize(BOOL bCalcValidRects,NCCALCSIZE_PARAMS FAR * lpncsp)4403 void CXYWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR *lpncsp) {
4404 	CWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
4405 }
4406 
4407 /*
4408  =======================================================================================================================
4409  =======================================================================================================================
4410  */
OnKillFocus(CWnd * pNewWnd)4411 void CXYWnd::OnKillFocus(CWnd *pNewWnd) {
4412 	CWnd::OnKillFocus(pNewWnd);
4413 	SendMessage(WM_NCACTIVATE, FALSE, 0);
4414 }
4415 
4416 /*
4417  =======================================================================================================================
4418  =======================================================================================================================
4419  */
OnSetFocus(CWnd * pOldWnd)4420 void CXYWnd::OnSetFocus(CWnd *pOldWnd) {
4421 	CWnd::OnSetFocus(pOldWnd);
4422 	SendMessage(WM_NCACTIVATE, TRUE, 0);
4423 }
4424 
4425 /*
4426  =======================================================================================================================
4427  =======================================================================================================================
4428  */
OnClose()4429 void CXYWnd::OnClose() {
4430 	CWnd::OnClose();
4431 }
4432 
4433 //
4434 // =======================================================================================================================
4435 //    should be static as should be the rotate scale stuff
4436 // =======================================================================================================================
4437 //
AreaSelectOK()4438 bool CXYWnd::AreaSelectOK() {
4439 	return RotateMode() ? false : ScaleMode() ? false : true;
4440 }
4441 
4442 /*
4443  =======================================================================================================================
4444  =======================================================================================================================
4445  */
OnEraseBkgnd(CDC * pDC)4446 BOOL CXYWnd::OnEraseBkgnd(CDC *pDC) {
4447 	return TRUE;
4448 
4449 	// return CWnd::OnEraseBkgnd(pDC);
4450 }
4451 
4452 extern void AssignModel();
OnDropNewmodel()4453 void CXYWnd::OnDropNewmodel()
4454 {
4455 	CPoint point;
4456 	GetCursorPos(&point);
4457 	CreateRightClickEntity(this, m_ptDown.x, m_ptDown.y, "func_static");
4458 	g_Inspectors->SetMode(W_ENTITY);
4459 	g_Inspectors->AssignModel();
4460 }
4461 
OnMouseWheel(UINT nFlags,short zDelta,CPoint pt)4462 BOOL CXYWnd::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
4463 {
4464 	if (zDelta > 0) {
4465 		g_pParentWnd->OnViewZoomin();
4466 	} else {
4467 		g_pParentWnd->OnViewZoomout();
4468 	}
4469 	return TRUE;
4470 }
4471 
4472 
4473 
4474 
4475  //---------------------------------------------------------------------------
4476  // CyclePrecisionCrosshairMode
4477  //
4478  // Called when the user presses the "cycle precision cursor mode" key.
4479  // Cycles the precision cursor among the following three modes:
4480  //		PRECISION_CURSOR_NONE
4481  //		PRECISION_CURSOR_SNAP
4482  //		PRECISION_CURSOR_FREE
4483  //---------------------------------------------------------------------------
CyclePrecisionCrosshairMode(void)4484  void CXYWnd::CyclePrecisionCrosshairMode( void )
4485  {
4486 	 common->Printf("TODO: Make DrawPrecisionCrosshair work..." );
4487 
4488 	 /// Cycle to next mode, wrap if necessary
4489 	 m_precisionCrosshairMode ++;
4490 	 if( m_precisionCrosshairMode >= PRECISION_CROSSHAIR_MAX )
4491 		 m_precisionCrosshairMode = PRECISION_CROSSHAIR_NONE;
4492 	 Sys_UpdateWindows( W_XY );
4493  }
4494 
4495  //---------------------------------------------------------------------------
4496 // DrawPrecisionCrosshair
4497 //
4498 // Draws a precision crosshair beneath the cursor in the 2d (XY) view,
4499 //  depending on one of the following values for m_precisionCrosshairMode:
4500 //
4501 // PRECISION_CROSSHAIR_NONE		No crosshair is drawn.  Do not force refresh of XY view.
4502 // PRECISION_CROSSHAIR_SNAP		Crosshair snaps to grid size.  Force refresh of XY view.
4503 // PRECISION_CROSSHAIR_FREE		Crosshair does not snap to grid.  Force refresh of XY view.
4504 //---------------------------------------------------------------------------
DrawPrecisionCrosshair(void)4505 void CXYWnd::DrawPrecisionCrosshair( void )
4506 {
4507 	// FIXME: m_mouseX, m_mouseY, m_axisHoriz, m_axisVert, etc... are never set
4508 	return;
4509 
4510 	idVec3 mouse3dPos (0.0f, 0.0f, 0.0f);
4511 	float x, y;
4512 	idVec4 crossEndColor (1.0f, 0.0f, 1.0f, 1.0f); // the RGBA color of the precision crosshair at its ends
4513 	idVec4 crossMidColor; // the RGBA color of the precision crosshair at the crossing point
4514 
4515 	/// Transform the mouse coordinates into axis-correct map-coordinates
4516 	if( m_precisionCrosshairMode == PRECISION_CROSSHAIR_SNAP )
4517 		SnapToPoint( m_mouseX, m_mouseY, mouse3dPos );
4518 	else
4519 		XY_ToPoint( m_mouseX, m_mouseY, mouse3dPos );
4520 	x = mouse3dPos[ m_axisHoriz ];
4521 	y = mouse3dPos[ m_axisVert ];
4522 
4523 	/// Use the color specified by the user
4524 
4525 	crossEndColor[0] = g_qeglobals.d_savedinfo.colors[ COLOR_PRECISION_CROSSHAIR ][0];
4526 	crossEndColor[1] = g_qeglobals.d_savedinfo.colors[ COLOR_PRECISION_CROSSHAIR ][1];
4527 	crossEndColor[2] = g_qeglobals.d_savedinfo.colors[ COLOR_PRECISION_CROSSHAIR ][2];
4528 	crossEndColor[3] = 1.0f;
4529 
4530 	crossMidColor = crossEndColor;
4531 
4532 	if( m_precisionCrosshairMode == PRECISION_CROSSHAIR_FREE )
4533 		crossMidColor[ 3 ] = 0.0f; // intersection-color is 100% transparent (alpha = 0.0f)
4534 
4535 	/// Set up OpenGL states (for drawing smooth-shaded plain-colored lines)
4536 	qglEnable( GL_BLEND );
4537 	qglDisable( GL_TEXTURE_2D );
4538 	qglShadeModel( GL_SMOOTH );
4539 	qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
4540 
4541 	/// Draw a fullscreen-sized crosshair over the cursor
4542 	qglBegin( GL_LINES );
4543 	{
4544 		/// Draw the horizontal precision line (in two pieces)
4545 		qglColor4fv( crossEndColor.ToFloatPtr() );
4546 		qglVertex2f( m_mcLeft, y );
4547 		qglColor4fv( crossMidColor.ToFloatPtr() );
4548 		qglVertex2f( x, y );
4549 		qglColor4fv( crossMidColor.ToFloatPtr() );
4550 		qglVertex2f( x, y );
4551 		qglColor4fv( crossEndColor.ToFloatPtr() );
4552 		qglVertex2f( m_mcRight, y );
4553 
4554 		/// Draw the vertical precision line (in two pieces)
4555 		qglColor4fv( crossEndColor.ToFloatPtr() );
4556 		qglVertex2f( x, m_mcTop );
4557 		qglColor4fv( crossMidColor.ToFloatPtr() );
4558 		qglVertex2f( x, y );
4559 		qglColor4fv( crossMidColor.ToFloatPtr() );
4560 		qglVertex2f( x, y );
4561 		qglColor4fv( crossEndColor.ToFloatPtr() );
4562 		qglVertex2f( x, m_mcBottom );
4563 	}
4564 	qglEnd(); // GL_LINES
4565 
4566 	// Radiant was in opaque, flat-shaded mode by default; restore this to prevent possible slowdown
4567 	qglShadeModel( GL_FLAT );
4568 	qglDisable( GL_BLEND );
4569 }
4570