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 "CamWnd.h"
36 #include "splines.h"
37 #include <GL/glu.h>
38 
39 #include "../../renderer/tr_local.h"
40 #include "../../renderer/model_local.h"	// for idRenderModelMD5
41 
42 
43 // TODO: DG: could merge SteelStorm2 "new 3D view navigation" improvements
44 
45 #ifdef _DEBUG
46 	#define new DEBUG_NEW
47 	#undef THIS_FILE
48 static char THIS_FILE[] = __FILE__;
49 #endif
50 extern void DrawPathLines();
51 
52 int g_axialAnchor = -1;
53 int g_axialDest = -1;
54 bool g_bAxialMode = false;
55 
ValidateAxialPoints()56 void ValidateAxialPoints() {
57 	int faceCount = g_ptrSelectedFaces.GetSize();
58 	if (faceCount > 0) {
59 		face_t	*selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(0));
60 		if (g_axialAnchor >= selFace->face_winding->GetNumPoints()) {
61 			g_axialAnchor = 0;
62 		}
63 		if (g_axialDest >= selFace->face_winding->GetNumPoints()) {
64 			g_axialDest = 0;
65 		}
66 	} else {
67 		g_axialDest = 0;
68 		g_axialAnchor = 0;
69 	}
70 }
71 
72 // CCamWnd
73 IMPLEMENT_DYNCREATE(CCamWnd, CWnd);
74 
75 /*
76  =======================================================================================================================
77  =======================================================================================================================
78  */
CCamWnd()79 CCamWnd::CCamWnd() {
80 	m_pXYFriend = NULL;
81 	memset(&m_Camera, 0, sizeof(camera_t));
82 	m_pSide_select = NULL;
83 	m_bClipMode = false;
84 	worldDirty = true;
85 	worldModel = NULL;
86 	renderMode = false;
87 	rebuildMode = false;
88 	entityMode = false;
89 	animationMode = false;
90 	selectMode = false;
91 	soundMode = false;
92 	saveValid = false;
93 	Cam_Init();
94 }
95 
96 /*
97  =======================================================================================================================
98  =======================================================================================================================
99  */
~CCamWnd()100 CCamWnd::~CCamWnd() {
101 }
102 
BEGIN_MESSAGE_MAP(CCamWnd,CWnd)103 BEGIN_MESSAGE_MAP(CCamWnd, CWnd)
104 //{{AFX_MSG_MAP(CCamWnd)
105 	ON_WM_KEYDOWN()
106 	ON_WM_PAINT()
107 	ON_WM_DESTROY()
108 	ON_WM_CLOSE()
109 	ON_WM_MOUSEMOVE()
110 	ON_WM_LBUTTONDOWN()
111 	ON_WM_LBUTTONUP()
112 	ON_WM_MBUTTONDOWN()
113 	ON_WM_MBUTTONUP()
114 	ON_WM_RBUTTONDOWN()
115 	ON_WM_RBUTTONUP()
116 	ON_WM_CREATE()
117 	ON_WM_SIZE()
118 	ON_WM_KEYUP()
119 	ON_WM_NCCALCSIZE()
120 	ON_WM_KILLFOCUS()
121 	ON_WM_SETFOCUS()
122 	ON_WM_TIMER()
123 	//}}AFX_MSG_MAP
124 END_MESSAGE_MAP()
125 /*
126  =======================================================================================================================
127  =======================================================================================================================
128  */
129 LONG WINAPI CamWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
130 	RECT	rect;
131 
132 	GetClientRect(hWnd, &rect);
133 
134 	switch (uMsg)
135 	{
136 		case WM_KILLFOCUS:
137 		case WM_SETFOCUS:
138 			SendMessage(hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0);
139 			return 0;
140 
141 		case WM_NCCALCSIZE: // don't let windows copy pixels
142 			DefWindowProc(hWnd, uMsg, wParam, lParam);
143 			return WVR_REDRAW;
144 	}
145 
146 	return DefWindowProc(hWnd, uMsg, wParam, lParam);
147 }
148 
149 //
150 // =======================================================================================================================
151 //    CCamWnd message handlers
152 // =======================================================================================================================
153 //
PreCreateWindow(CREATESTRUCT & cs)154 BOOL CCamWnd::PreCreateWindow(CREATESTRUCT &cs) {
155 	WNDCLASS	wc;
156 	HINSTANCE	hInstance = AfxGetInstanceHandle();
157 	if (::GetClassInfo(hInstance, CAMERA_WINDOW_CLASS, &wc) == FALSE) {
158 		// Register a new class
159 		memset(&wc, 0, sizeof(wc));
160 
161 		// wc.style = CS_NOCLOSE | CS_OWNDC;
162 		wc.style = CS_NOCLOSE;
163 		wc.lpszClassName = CAMERA_WINDOW_CLASS;
164 		wc.hCursor = LoadCursor(NULL, IDC_ARROW);
165 		wc.lpfnWndProc = CamWndProc;
166 		if (AfxRegisterClass(&wc) == FALSE) {
167 			Error("CCamWnd RegisterClass: failed");
168 		}
169 	}
170 
171 	cs.lpszClass = CAMERA_WINDOW_CLASS;
172 	cs.lpszName = "CAM";
173 	if (cs.style != QE3_CHILDSTYLE) {
174 		cs.style = QE3_SPLITTER_STYLE;
175 	}
176 
177 	BOOL	bResult = CWnd::PreCreateWindow(cs);
178 
179 	//
180 	// See if the class already exists and if not then we need to register our new
181 	// window class.
182 	//
183 	return bResult;
184 }
185 
186 /*
187  =======================================================================================================================
188  =======================================================================================================================
189  */
OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)190 void CCamWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
191 	g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags);
192 }
193 
194 brush_t *g_pSplitList = NULL;
195 
196 /*
197  =======================================================================================================================
198  =======================================================================================================================
199  */
OnPaint()200 void CCamWnd::OnPaint() {
201 	CPaintDC	dc(this);	// device context for painting
202 	bool		bPaint = true;
203 
204 	if (!qwglMakeCurrent(dc.m_hDC, win32.hGLRC)) {
205 		common->Printf("ERROR: wglMakeCurrent failed..\n ");
206 		common->Printf("Please restart " EDITOR_WINDOWTEXT " if the camera view is not working\n");
207 	}
208 	else {
209 		QE_CheckOpenGLForErrors();
210 		g_pSplitList = NULL;
211 		if (g_bClipMode) {
212 			if (g_Clip1.Set() && g_Clip2.Set()) {
213 				g_pSplitList = ((g_pParentWnd->ActiveXY()->GetViewType() == XZ) ? !g_bSwitch : g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits;
214 			}
215 		}
216 
217 		Cam_Draw();
218 		QE_CheckOpenGLForErrors();
219 		qwglSwapBuffers(dc.m_hDC);
220 	}
221 }
222 
223 /*
224  =======================================================================================================================
225  =======================================================================================================================
226  */
SetXYFriend(CXYWnd * pWnd)227 void CCamWnd::SetXYFriend(CXYWnd *pWnd) {
228 	m_pXYFriend = pWnd;
229 }
230 
231 /*
232  =======================================================================================================================
233  =======================================================================================================================
234  */
OnDestroy()235 void CCamWnd::OnDestroy() {
236 	CWnd::OnDestroy();
237 }
238 
239 /*
240  =======================================================================================================================
241  =======================================================================================================================
242  */
OnClose()243 void CCamWnd::OnClose() {
244 	CWnd::OnClose();
245 }
246 
247 extern void Select_RotateTexture(float amt, bool absolute);
248 
249 /*
250  =======================================================================================================================
251  =======================================================================================================================
252  */
OnMouseMove(UINT nFlags,CPoint point)253 void CCamWnd::OnMouseMove(UINT nFlags, CPoint point) {
254 	CRect	r;
255 	GetClientRect(r);
256 	if	(GetCapture() == this && (GetAsyncKeyState(VK_MENU) & 0x8000) && !((GetAsyncKeyState(VK_SHIFT) & 0x8000) || (GetAsyncKeyState(VK_CONTROL) & 0x8000))) {
257 		if (GetAsyncKeyState(VK_CONTROL) & 0x8000) {
258 			Select_RotateTexture((float)point.y - m_ptLastCursor.y);
259 		}
260 		else if (GetAsyncKeyState(VK_SHIFT) & 0x8000) {
261 			Select_ScaleTexture((float)point.x - m_ptLastCursor.x, (float)m_ptLastCursor.y - point.y);
262 		}
263 		else {
264 			Select_ShiftTexture((float)point.x - m_ptLastCursor.x, (float)m_ptLastCursor.y - point.y);
265 		}
266 	}
267 	else {
268 		Cam_MouseMoved(point.x, r.bottom - 1 - point.y, nFlags);
269 	}
270 
271 	m_ptLastCursor = point;
272 }
273 
274 /*
275  =======================================================================================================================
276  =======================================================================================================================
277  */
OnLButtonDown(UINT nFlags,CPoint point)278 void CCamWnd::OnLButtonDown(UINT nFlags, CPoint point) {
279 	m_ptLastCursor = point;
280 	OriginalMouseDown(nFlags, point);
281 }
282 
283 /*
284  =======================================================================================================================
285  =======================================================================================================================
286  */
OnLButtonUp(UINT nFlags,CPoint point)287 void CCamWnd::OnLButtonUp(UINT nFlags, CPoint point) {
288 	OriginalMouseUp(nFlags, point);
289 }
290 
291 /*
292  =======================================================================================================================
293  =======================================================================================================================
294  */
OnMButtonDown(UINT nFlags,CPoint point)295 void CCamWnd::OnMButtonDown(UINT nFlags, CPoint point) {
296 	OriginalMouseDown(nFlags, point);
297 }
298 
299 /*
300  =======================================================================================================================
301  =======================================================================================================================
302  */
OnMButtonUp(UINT nFlags,CPoint point)303 void CCamWnd::OnMButtonUp(UINT nFlags, CPoint point) {
304 	OriginalMouseUp(nFlags, point);
305 }
306 
307 /*
308  =======================================================================================================================
309  =======================================================================================================================
310  */
OnRButtonDown(UINT nFlags,CPoint point)311 void CCamWnd::OnRButtonDown(UINT nFlags, CPoint point) {
312 	OriginalMouseDown(nFlags, point);
313 }
314 
315 /*
316  =======================================================================================================================
317  =======================================================================================================================
318  */
OnRButtonUp(UINT nFlags,CPoint point)319 void CCamWnd::OnRButtonUp(UINT nFlags, CPoint point) {
320 	OriginalMouseUp(nFlags, point);
321 }
322 
323 /*
324  =======================================================================================================================
325  =======================================================================================================================
326  */
OnCreate(LPCREATESTRUCT lpCreateStruct)327 int CCamWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
328 	if (CWnd::OnCreate(lpCreateStruct) == -1) {
329 		return -1;
330 	}
331 
332 	CDC *pDC = GetDC();
333 	HDC hDC = pDC->GetSafeHdc();
334 
335 	QEW_SetupPixelFormat(hDC, true);
336 
337 	HFONT hfont = CreateFont(
338 				12,	// logical height of font
339 				0,	// logical average character width
340 				0,	// angle of escapement
341 				0,	// base-line orientation angle
342 				0,	// font weight
343 				0,	// italic attribute flag
344 				0,	// underline attribute flag
345 				0,	// strikeout attribute flag
346 				0,	// character set identifier
347 				0,	// output precision
348 				0,	// clipping precision
349 				0,	// output quality
350 				FIXED_PITCH | FF_MODERN,	// pitch and family
351 				"Lucida Console"	// pointer to typeface name string
352 				);
353 
354 	if (!hfont) {
355 		Error("couldn't create font");
356 	}
357 
358 	HFONT hOldFont = (HFONT)SelectObject(hDC, hfont);
359 
360 	//qwglMakeCurrent (hDC, win32.hGLRC);
361 	if( qwglMakeCurrent ( hDC, win32.hGLRC ) == FALSE ) {
362 		common->Warning("wglMakeCurrent failed: %d", ::GetLastError());
363 		if ( r_multiSamples.GetInteger() > 0 ) {
364 			common->Warning("\n!!! Remember to set r_multiSamples 0 when using the editor !!!\n");
365 		}
366 	}
367 
368 	if ((g_qeglobals.d_font_list = qglGenLists(256)) == 0) {
369 		common->Warning( "couldn't create font dlists" );
370 	}
371 
372 	// create the bitmap display lists we're making images of glyphs 0 thru 255
373 	if ( !qwglUseFontBitmaps(hDC, 0, 255, g_qeglobals.d_font_list) ) {
374 		common->Warning( "wglUseFontBitmaps failed (%d).  Trying again.", GetLastError() );
375 
376 		// FIXME: This is really wacky, sometimes the first call fails, but calling it again makes it work
377 		//		This probably indicates there's something wrong somewhere else in the code, but I'm not sure what
378 		if ( !qwglUseFontBitmaps(hDC, 0, 255, g_qeglobals.d_font_list) ) {
379 			common->Warning( "wglUseFontBitmaps failed again (%d).  Trying outlines.", GetLastError() );
380 
381 			if (!qwglUseFontOutlines(hDC, 0, 255, g_qeglobals.d_font_list, 0.0f, 0.1f, WGL_FONT_LINES, NULL)) {
382 				common->Warning( "wglUseFontOutlines also failed (%d), no coordinate text will be visible.", GetLastError() );
383 			}
384 		}
385 	}
386 
387 	SelectObject(hDC, hOldFont);
388 	ReleaseDC(pDC);
389 
390 	// indicate start of glyph display lists
391 	qglListBase(g_qeglobals.d_font_list);
392 
393 	// report OpenGL information
394 	common->Printf("GL_VENDOR: %s\n", qglGetString(GL_VENDOR));
395 	common->Printf("GL_RENDERER: %s\n", qglGetString(GL_RENDERER));
396 	common->Printf("GL_VERSION: %s\n", qglGetString(GL_VERSION));
397 	common->Printf("GL_EXTENSIONS: %s\n", qglGetString(GL_EXTENSIONS));
398 
399 	return 0;
400 }
401 
402 /*
403  =======================================================================================================================
404  =======================================================================================================================
405  */
OriginalMouseUp(UINT nFlags,CPoint point)406 void CCamWnd::OriginalMouseUp(UINT nFlags, CPoint point) {
407 	CRect	r;
408 	GetClientRect(r);
409 	Cam_MouseUp(point.x, r.bottom - 1 - point.y, nFlags);
410 	if (!(nFlags & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON))) {
411 		ReleaseCapture();
412 	}
413 }
414 
415 /*
416  =======================================================================================================================
417  =======================================================================================================================
418  */
OriginalMouseDown(UINT nFlags,CPoint point)419 void CCamWnd::OriginalMouseDown(UINT nFlags, CPoint point) {
420 	// if (GetTopWindow()->GetSafeHwnd() != GetSafeHwnd()) BringWindowToTop();
421 	CRect	r;
422 	GetClientRect(r);
423 	SetFocus();
424 	SetCapture();
425 
426 	// if (!(GetAsyncKeyState(VK_MENU) & 0x8000))
427 	Cam_MouseDown(point.x, r.bottom - 1 - point.y, nFlags);
428 }
429 
430 /*
431  =======================================================================================================================
432  =======================================================================================================================
433  */
Cam_Init()434 void CCamWnd::Cam_Init() {
435 	// m_Camera.draw_mode = cd_texture;
436 	m_Camera.origin[0] = 0.0f;
437 	m_Camera.origin[1] = 20.0f;
438 	m_Camera.origin[2] = 72.0f;
439 	m_Camera.color[0] = 0.3f;
440 	m_Camera.color[1] = 0.3f;
441 	m_Camera.color[2] = 0.3f;
442 }
443 
444 /*
445  =======================================================================================================================
446  =======================================================================================================================
447  */
Cam_BuildMatrix()448 void CCamWnd::Cam_BuildMatrix() {
449 	float	xa, ya;
450 	float	matrix[4][4];
451 	int		i;
452 
453 	xa = ((renderMode) ? -m_Camera.angles[PITCH] : m_Camera.angles[PITCH]) * idMath::M_DEG2RAD;
454 	ya = m_Camera.angles[YAW] * idMath::M_DEG2RAD;
455 
456 	// the movement matrix is kept 2d
457 	m_Camera.forward[0] = cos(ya);
458 	m_Camera.forward[1] = sin(ya);
459 	m_Camera.right[0] = m_Camera.forward[1];
460 	m_Camera.right[1] = -m_Camera.forward[0];
461 
462 	qglGetFloatv(GL_PROJECTION_MATRIX, &matrix[0][0]);
463 
464 	for (i = 0; i < 3; i++) {
465 		m_Camera.vright[i] = matrix[i][0];
466 		m_Camera.vup[i] = matrix[i][1];
467 		m_Camera.vpn[i] = matrix[i][2];
468 	}
469 
470 	m_Camera.vright.Normalize();
471 	m_Camera.vup.Normalize();
472 	m_Camera.vpn.Normalize();
473 	InitCull();
474 }
475 
476 /*
477  =======================================================================================================================
478  =======================================================================================================================
479  */
480 
Cam_ChangeFloor(bool up)481 void CCamWnd::Cam_ChangeFloor(bool up) {
482 	brush_t *b;
483 	float	d, bestd, current;
484 	idVec3	start, dir;
485 
486 	start[0] = m_Camera.origin[0];
487 	start[1] = m_Camera.origin[1];
488 	start[2] = HUGE_DISTANCE;
489 	dir[0] = dir[1] = 0;
490 	dir[2] = -1;
491 
492 	current = HUGE_DISTANCE - (m_Camera.origin[2] - 72);
493 	if (up) {
494 		bestd = 0;
495 	}
496 	else {
497 		bestd = HUGE_DISTANCE*2;
498 	}
499 
500 	for (b = active_brushes.next; b != &active_brushes; b = b->next) {
501 		if (!Brush_Ray(start, dir, b, &d)) {
502 			continue;
503 		}
504 
505 		if (up && d < current && d > bestd) {
506 			bestd = d;
507 		}
508 
509 		if (!up && d > current && d < bestd) {
510 			bestd = d;
511 		}
512 	}
513 
514 	if (bestd == 0 || bestd == HUGE_DISTANCE*2) {
515 		return;
516 	}
517 
518 	m_Camera.origin[2] += current - bestd;
519 	Sys_UpdateWindows(W_CAMERA | W_Z_OVERLAY);
520 }
521 
522 /*
523  =======================================================================================================================
524  =======================================================================================================================
525  */
Cam_PositionDrag()526 void CCamWnd::Cam_PositionDrag() {
527 	int x, y;
528 	Sys_GetCursorPos(&x, &y);
529 	if (x != m_ptCursor.x || y != m_ptCursor.y) {
530 		x -= m_ptCursor.x;
531 		VectorMA(m_Camera.origin, x, m_Camera.vright, m_Camera.origin);
532 		y -= m_ptCursor.y;
533 		m_Camera.origin[2] -= y;
534 		SetCursorPos(m_ptCursor.x, m_ptCursor.y);
535 		Sys_UpdateWindows(W_CAMERA | W_XY_OVERLAY);
536 	}
537 }
538 
Cam_MouseLook()539 void CCamWnd::Cam_MouseLook() {
540 	CPoint current;
541 
542 	GetCursorPos(&current);
543 	if (current.x != m_ptCursor.x || current.y != m_ptCursor.y) {
544 
545 		current.x -= m_ptCursor.x;
546 		current.y -= m_ptCursor.y;
547 
548 		m_Camera.angles[PITCH] -= (float)((float)current.y * 0.25f);
549 		m_Camera.angles[YAW] -= (float)((float)current.x * 0.25f);
550 
551 		SetCursorPos(m_ptCursor.x, m_ptCursor.y);
552 
553 		Cam_BuildMatrix();
554 	}
555 }
556 
557 /*
558  =======================================================================================================================
559  =======================================================================================================================
560  */
Cam_MouseControl(float dtime)561 void CCamWnd::Cam_MouseControl(float dtime) {
562 	int		xl, xh;
563 	int		yl, yh;
564 	float	xf, yf;
565 	if (g_PrefsDlg.m_nMouseButtons == 2) {
566 		if (m_nCambuttonstate != (MK_RBUTTON | MK_SHIFT)) {
567 			return;
568 		}
569 	}
570 	else {
571 		if (m_nCambuttonstate != MK_RBUTTON) {
572 			return;
573 		}
574 	}
575 
576 	xf = (float)(m_ptButton.x - m_Camera.width / 2) / (m_Camera.width / 2);
577 	yf = (float)(m_ptButton.y - m_Camera.height / 2) / (m_Camera.height / 2);
578 
579 	xl = m_Camera.width / 3;
580 	xh = xl * 2;
581 	yl = m_Camera.height / 3;
582 	yh = yl * 2;
583 
584 	// common->Printf("xf-%f yf-%f xl-%i xh-i% yl-i% yh-i%\n",xf,yf,xl,xh,yl,yh);
585 #if 0
586 
587 	// strafe
588 	if (buttony < yl && (buttonx < xl || buttonx > xh)) {
589 		VectorMA(camera.origin, xf * dtime * g_nMoveSpeed, camera.right, camera.origin);
590 	}
591 	else
592 #endif
593 	{
594 		xf *= 1.0f - idMath::Fabs(yf);
595 		if ( xf < 0.0f ) {
596 			xf += 0.1f;
597 			if ( xf > 0.0f ) {
598 				xf = 0.0f;
599 			}
600 		}
601 		else {
602 			xf -= 0.1f;
603 			if ( xf < 0.0f ) {
604 				xf = 0.0f;
605 			}
606 		}
607 
608 		VectorMA(m_Camera.origin, yf * dtime * g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin);
609 		m_Camera.angles[YAW] += xf * -dtime * g_PrefsDlg.m_nAngleSpeed;
610 	}
611 
612 	Cam_BuildMatrix();
613 	int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA);
614 	Sys_UpdateWindows(nUpdate);
615 	g_pParentWnd->PostMessage(WM_TIMER, 0, 0);
616 }
617 
618 /*
619  =======================================================================================================================
620  =======================================================================================================================
621  */
Cam_MouseDown(int x,int y,int buttons)622 void CCamWnd::Cam_MouseDown(int x, int y, int buttons) {
623 	idVec3	dir;
624 	float	f, r, u;
625 	int		i;
626 
627 	// calc ray direction
628 	u = (float)(y - m_Camera.height / 2) / (m_Camera.width / 2);
629 	r = (float)(x - m_Camera.width / 2) / (m_Camera.width / 2);
630 	f = 1;
631 
632 	for (i = 0; i < 3; i++) {
633 		dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u;
634 	}
635 
636 	dir.Normalize();
637 
638 	GetCursorPos(&m_ptCursor);
639 
640 	m_nCambuttonstate = buttons;
641 	m_ptButton.x = x;
642 	m_ptButton.y = y;
643 
644 	//
645 	// LBUTTON = manipulate selection shift-LBUTTON = select middle button = grab
646 	// texture ctrl-middle button = set entire brush to texture ctrl-shift-middle
647 	// button = set single face to texture
648 	//
649 	int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
650 	if
651 	(
652 		(buttons == MK_LBUTTON) ||
653 		(buttons == (MK_LBUTTON | MK_SHIFT)) ||
654 		(buttons == (MK_LBUTTON | MK_CONTROL)) ||
655 		(buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ||
656 		(buttons == nMouseButton) ||
657 		(buttons == (nMouseButton | MK_SHIFT)) ||
658 		(buttons == (nMouseButton | MK_CONTROL)) ||
659 		(buttons == (nMouseButton | MK_SHIFT | MK_CONTROL))
660 	) {
661 		if (g_PrefsDlg.m_nMouseButtons == 2 && (buttons == (MK_RBUTTON | MK_SHIFT))) {
662 			Cam_MouseControl( 0.1f );
663 		}
664 		else {
665 			// something global needs to track which window is responsible for stuff
666 			Patch_SetView(W_CAMERA);
667 			Drag_Begin(x, y, buttons, m_Camera.vright, m_Camera.vup, m_Camera.origin, dir);
668 		}
669 
670 		return;
671 	}
672 
673 	if ( buttons == MK_RBUTTON ) {
674 		Cam_MouseControl( 0.1f );
675 		return;
676 	}
677 }
678 
679 /*
680  =======================================================================================================================
681  =======================================================================================================================
682  */
Cam_MouseUp(int x,int y,int buttons)683 void CCamWnd::Cam_MouseUp(int x, int y, int buttons) {
684 	m_nCambuttonstate = 0;
685 	Drag_MouseUp(buttons);
686 }
687 
688 /*
689  =======================================================================================================================
690  =======================================================================================================================
691  */
Cam_MouseMoved(int x,int y,int buttons)692 void CCamWnd::Cam_MouseMoved(int x, int y, int buttons) {
693 	m_nCambuttonstate = buttons;
694 	if (!buttons) {
695 		return;
696 	}
697 
698 	m_ptButton.x = x;
699 	m_ptButton.y = y;
700 
701 	if (buttons == (MK_RBUTTON | MK_CONTROL)) {
702 		Cam_PositionDrag();
703 		Sys_UpdateWindows(W_XY | W_CAMERA | W_Z);
704 		return;
705 	}
706 	else if ( buttons == (MK_RBUTTON | MK_CONTROL | MK_SHIFT) ) {
707 		Cam_MouseLook();
708 		Sys_UpdateWindows(W_XY | W_CAMERA | W_Z);
709 		return;
710 	}
711 
712 	GetCursorPos(&m_ptCursor);
713 
714 	if (buttons & (MK_LBUTTON | MK_MBUTTON)) {
715 		Drag_MouseMoved(x, y, buttons);
716 		Sys_UpdateWindows(W_XY | W_CAMERA | W_Z);
717 	}
718 }
719 
720 /*
721  =======================================================================================================================
722  =======================================================================================================================
723  */
InitCull()724 void CCamWnd::InitCull() {
725 	int i;
726 
727 	VectorSubtract(m_Camera.vpn, m_Camera.vright, m_vCull1);
728 	VectorAdd(m_Camera.vpn, m_Camera.vright, m_vCull2);
729 
730 	for (i = 0; i < 3; i++) {
731 		if (m_vCull1[i] > 0) {
732 			m_nCullv1[i] = 3 + i;
733 		}
734 		else {
735 			m_nCullv1[i] = i;
736 		}
737 
738 		if (m_vCull2[i] > 0) {
739 			m_nCullv2[i] = 3 + i;
740 		}
741 		else {
742 			m_nCullv2[i] = i;
743 		}
744 	}
745 }
746 
747 /*
748  =======================================================================================================================
749  =======================================================================================================================
750  */
CullBrush(brush_t * b,bool cubicOnly)751 bool CCamWnd::CullBrush(brush_t *b, bool cubicOnly) {
752 	int		i;
753 	idVec3	point;
754 	float	d;
755 
756 	if ( b->forceVisibile ) {
757 		return false;
758 	}
759 
760 	if (g_PrefsDlg.m_bCubicClipping) {
761 
762 		float distance = g_PrefsDlg.m_nCubicScale * 64;
763 
764 		idVec3 mid;
765 		for (int i = 0; i < 3; i++) {
766 			mid[i] = (b->mins[i] + ((b->maxs[i] - b->mins[i]) / 2));
767 		}
768 
769 		point = mid - m_Camera.origin;
770 		if (point.Length() > distance) {
771 			return true;
772 		}
773 
774 	}
775 
776 	if (cubicOnly) {
777 		return false;
778 	}
779 
780 	for (i = 0; i < 3; i++) {
781 		point[i] = b->mins[m_nCullv1[i]] - m_Camera.origin[i];
782 	}
783 
784 	d = DotProduct(point, m_vCull1);
785 	if (d < -1) {
786 		return true;
787 	}
788 
789 	for (i = 0; i < 3; i++) {
790 		point[i] = b->mins[m_nCullv2[i]] - m_Camera.origin[i];
791 	}
792 
793 	d = DotProduct(point, m_vCull2);
794 	if (d < -1) {
795 		return true;
796 	}
797 
798 	return false;
799 }
800 
801 #if 0
802 
803 /*
804  =======================================================================================================================
805  =======================================================================================================================
806  */
807 void CCamWnd::DrawLightRadius(brush_t *pBrush) {
808 	// if lighting
809 	int nRadius = Brush_LightRadius(pBrush);
810 	if (nRadius > 0) {
811 		Brush_SetLightColor(pBrush);
812 		qglEnable(GL_BLEND);
813 		qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
814 		qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
815 		qglDisable(GL_BLEND);
816 		qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
817 	}
818 }
819 #endif
820 
821 /*
822  =======================================================================================================================
823  =======================================================================================================================
824  */
setGLMode(int mode)825 void setGLMode(int mode) {
826 	switch (mode)
827 	{
828 		case cd_wire:
829 			qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
830 			globalImages->BindNull();
831 			qglDisable(GL_BLEND);
832 			qglDisable(GL_DEPTH_TEST);
833 			qglColor3f( 1.0f, 1.0f, 1.0f );
834 			break;
835 
836 		case cd_solid:
837 			qglCullFace(GL_FRONT);
838 			qglEnable(GL_CULL_FACE);
839 			qglShadeModel(GL_FLAT);
840 			qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
841 			globalImages->BindNull();
842 			qglDisable(GL_BLEND);
843 			qglEnable(GL_DEPTH_TEST);
844 			qglDepthFunc(GL_LEQUAL);
845 			break;
846 
847 		case cd_texture:
848 			qglCullFace(GL_FRONT);
849 			qglEnable(GL_CULL_FACE);
850 			qglShadeModel(GL_FLAT);
851 			qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
852 			qglDisable(GL_BLEND);
853 			qglEnable(GL_DEPTH_TEST);
854 			qglDepthFunc(GL_LEQUAL);
855 			break;
856 
857 		case cd_blend:
858 			qglCullFace(GL_FRONT);
859 			qglEnable(GL_CULL_FACE);
860 			qglShadeModel(GL_FLAT);
861 			qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
862 			qglDisable(GL_DEPTH_TEST);
863 			qglEnable(GL_BLEND);
864 			qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
865 			break;
866 	}
867 }
868 
869 
870 extern void glLabeledPoint(idVec4 &color, idVec3 &point, float size, const char *label);
DrawAxial(face_t * selFace)871 void DrawAxial(face_t *selFace) {
872 	if (g_bAxialMode) {
873 		idVec3 points[4];
874 
875 		for (int j = 0; j < selFace->face_winding->GetNumPoints(); j++) {
876 			glLabeledPoint(idVec4(1, 1, 1, 1), (*selFace->face_winding)[j].ToVec3(), 3, va("%i", j));
877 		}
878 
879 		ValidateAxialPoints();
880 		points[0] = (*selFace->face_winding)[g_axialAnchor].ToVec3();
881 		VectorMA (points[0], 1, selFace->plane, points[0]);
882 		VectorMA (points[0], 4, selFace->plane, points[1]);
883 		points[3] = (*selFace->face_winding)[g_axialDest].ToVec3();
884 		VectorMA (points[3], 1, selFace->plane, points[3]);
885 		VectorMA (points[3], 4, selFace->plane, points[2]);
886 		glLabeledPoint(idVec4(1, 0, 0, 1), points[1], 3, "Anchor");
887 		glLabeledPoint(idVec4(1, 1, 0, 1), points[2], 3, "Dest");
888 		qglBegin (GL_LINE_STRIP);
889 		qglVertex3fv( points[0].ToFloatPtr() );
890 		qglVertex3fv( points[1].ToFloatPtr() );
891 		qglVertex3fv( points[2].ToFloatPtr() );
892 		qglVertex3fv( points[3].ToFloatPtr() );
893 		qglEnd();
894 	}
895 }
896 
897 
898 /*
899  =======================================================================================================================
900 	Cam_Draw
901  =======================================================================================================================
902  */
SetProjectionMatrix()903 void CCamWnd::SetProjectionMatrix() {
904 	float xfov = 90;
905 	float yfov = 2 * atan((float)m_Camera.height / m_Camera.width) * idMath::M_RAD2DEG;
906 #if 0
907 	float screenaspect = (float)m_Camera.width / m_Camera.height;
908 	qglLoadIdentity();
909 	gluPerspective(yfov, screenaspect, 2, 8192);
910 #else
911 	float	xmin, xmax, ymin, ymax;
912 	float	width, height;
913 	float	zNear;
914 	float	projectionMatrix[16];
915 
916 	//
917 	// set up projection matrix
918 	//
919 	zNear	= r_znear.GetFloat();
920 
921 	ymax = zNear * tan( yfov * idMath::PI / 360.0f );
922 	ymin = -ymax;
923 
924 	xmax = zNear * tan( xfov * idMath::PI / 360.0f );
925 	xmin = -xmax;
926 
927 	width = xmax - xmin;
928 	height = ymax - ymin;
929 
930 	projectionMatrix[0] = 2 * zNear / width;
931 	projectionMatrix[4] = 0;
932 	projectionMatrix[8] = ( xmax + xmin ) / width;	// normally 0
933 	projectionMatrix[12] = 0;
934 
935 	projectionMatrix[1] = 0;
936 	projectionMatrix[5] = 2 * zNear / height;
937 	projectionMatrix[9] = ( ymax + ymin ) / height;	// normally 0
938 	projectionMatrix[13] = 0;
939 
940 	// this is the far-plane-at-infinity formulation
941 	projectionMatrix[2] = 0;
942 	projectionMatrix[6] = 0;
943 	projectionMatrix[10] = -1;
944 	projectionMatrix[14] = -2 * zNear;
945 
946 	projectionMatrix[3] = 0;
947 	projectionMatrix[7] = 0;
948 	projectionMatrix[11] = -1;
949 	projectionMatrix[15] = 0;
950 
951 	qglLoadMatrixf( projectionMatrix );
952 #endif
953 }
954 
Cam_Draw()955 void CCamWnd::Cam_Draw() {
956 	brush_t *brush;
957 	face_t	*face;
958 
959 	// float yfov;
960 	int		i;
961 
962 	if (!active_brushes.next) {
963 		return;					// not valid yet
964 	}
965 
966 	// set the sound origin for both simple draw and rendered mode
967 	// the editor uses opposite pitch convention
968 	idMat3	axis = idAngles( -m_Camera.angles.pitch, m_Camera.angles.yaw, m_Camera.angles.roll ).ToMat3();
969 	g_qeglobals.sw->PlaceListener( m_Camera.origin, axis, 0, Sys_Milliseconds(), "Undefined" );
970 
971 	if (renderMode) {
972 		Cam_Render();
973 	}
974 
975 	qglViewport(0, 0, m_Camera.width, m_Camera.height);
976 	qglScissor(0, 0, m_Camera.width, m_Camera.height);
977 	qglClearColor(g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0], g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1], g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], 0);
978 
979 	if (!renderMode) {
980 		qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
981 	}
982 
983 	qglDisable(GL_LIGHTING);
984 	qglMatrixMode(GL_PROJECTION);
985 
986 	SetProjectionMatrix();
987 
988 	qglRotatef(-90, 1, 0, 0);	// put Z going up
989 	qglRotatef(90, 0, 0, 1);	// put Z going up
990 	qglRotatef(m_Camera.angles[0], 0, 1, 0);
991 	qglRotatef(-m_Camera.angles[1], 0, 0, 1);
992 	qglTranslatef(-m_Camera.origin[0], -m_Camera.origin[1], -m_Camera.origin[2]);
993 
994 	Cam_BuildMatrix();
995 
996 	for (brush = active_brushes.next; brush != &active_brushes; brush = brush->next) {
997 
998 		if ( CullBrush(brush, false) ) {
999 			continue;
1000 		}
1001 
1002 		if ( FilterBrush(brush) ) {
1003 			continue;
1004 		}
1005 
1006 		if (renderMode) {
1007 			if (!(entityMode && brush->owner->eclass->fixedsize)) {
1008 				continue;
1009 			}
1010 		}
1011 
1012 		setGLMode(m_Camera.draw_mode);
1013 		Brush_Draw(brush);
1014 	}
1015 
1016 
1017 	//qglDepthMask ( 1 ); // Ok, write now
1018 	qglMatrixMode(GL_PROJECTION);
1019 
1020 	qglTranslatef(g_qeglobals.d_select_translate[0],g_qeglobals.d_select_translate[1],g_qeglobals.d_select_translate[2]);
1021 
1022 	brush_t *pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes;
1023 
1024 	if (!renderMode) {
1025 		// draw normally
1026 		for (brush = pList->next; brush != pList; brush = brush->next) {
1027 			if (brush->pPatch) {
1028 				continue;
1029 			}
1030 			setGLMode(m_Camera.draw_mode);
1031 			Brush_Draw(brush, true);
1032 		}
1033 	}
1034 
1035 	// blend on top
1036 
1037 	setGLMode(m_Camera.draw_mode);
1038 	qglDisable(GL_LIGHTING);
1039 	qglColor4f( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0],g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1],g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2], 0.25f );
1040 	qglEnable(GL_BLEND);
1041 	qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1042 	qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1043 	globalImages->BindNull();
1044 	for (brush = pList->next; brush != pList; brush = brush->next) {
1045 		if (brush->pPatch || brush->modelHandle > 0) {
1046 			Brush_Draw(brush, true);
1047 
1048 			// DHM - Nerve:: patch display lists/models mess with the state
1049 			qglEnable(GL_BLEND);
1050 			qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1051 			qglColor4f( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0],g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1],g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2], 0.25f );
1052 			globalImages->BindNull();
1053 			continue;
1054 		}
1055 
1056 		if ( brush->owner->eclass->entityModel ) {
1057 			continue;
1058 		}
1059 
1060 		for (face = brush->brush_faces; face; face = face->next) {
1061 			Face_Draw(face);
1062 		}
1063 	}
1064 
1065 	int nCount = g_ptrSelectedFaces.GetSize();
1066 
1067 	if (!renderMode) {
1068 		for (int i = 0; i < nCount; i++) {
1069 			face_t	*selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
1070 			Face_Draw(selFace);
1071 			DrawAxial(selFace);
1072 		}
1073 	}
1074 
1075 	// non-zbuffered outline
1076 	qglDisable(GL_BLEND);
1077 	qglDisable(GL_DEPTH_TEST);
1078 	qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1079 
1080 	if (renderMode) {
1081 		qglColor3f(1, 0, 0);
1082 		for (int i = 0; i < nCount; i++) {
1083 			face_t	*selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
1084 			Face_Draw(selFace);
1085 		}
1086 	}
1087 
1088 	qglColor3f(1, 1, 1);
1089 	for (brush = pList->next; brush != pList; brush = brush->next) {
1090 		if (brush->pPatch || brush->modelHandle > 0) {
1091 			continue;
1092 		}
1093 
1094 		for (face = brush->brush_faces; face; face = face->next) {
1095 			Face_Draw(face);
1096 		}
1097 	}
1098 	// edge / vertex flags
1099 	if (g_qeglobals.d_select_mode == sel_vertex) {
1100 		qglPointSize(4);
1101 		qglColor3f(0, 1, 0);
1102 		qglBegin(GL_POINTS);
1103 		for (i = 0; i < g_qeglobals.d_numpoints; i++) {
1104 			qglVertex3fv( g_qeglobals.d_points[i].ToFloatPtr() );
1105 		}
1106 
1107 		qglEnd();
1108 		qglPointSize(1);
1109 	}
1110 	else if (g_qeglobals.d_select_mode == sel_edge) {
1111 		float	*v1, *v2;
1112 
1113 		qglPointSize(4);
1114 		qglColor3f(0, 0, 1);
1115 		qglBegin(GL_POINTS);
1116 		for (i = 0; i < g_qeglobals.d_numedges; i++) {
1117 			v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1].ToFloatPtr();
1118 			v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2].ToFloatPtr();
1119 			qglVertex3f( (v1[0] + v2[0]) * 0.5f, (v1[1] + v2[1]) * 0.5f, (v1[2] + v2[2]) * 0.5f );
1120 		}
1121 
1122 		qglEnd();
1123 		qglPointSize(1);
1124 	}
1125 
1126 	g_splineList->draw (static_cast<bool>(g_qeglobals.d_select_mode == sel_addpoint || g_qeglobals.d_select_mode == sel_editpoint));
1127 
1128 	if ( g_qeglobals.selectObject && (g_qeglobals.d_select_mode == sel_addpoint || g_qeglobals.d_select_mode == sel_editpoint) ) {
1129 		g_qeglobals.selectObject->drawSelection();
1130 	}
1131 
1132 	// draw pointfile
1133 	qglEnable(GL_DEPTH_TEST);
1134 
1135 	DrawPathLines();
1136 
1137 	if (g_qeglobals.d_pointfile_display_list) {
1138 		Pointfile_Draw();
1139 	}
1140 
1141 	//
1142 	// bind back to the default texture so that we don't have problems elsewhere
1143 	// using/modifying texture maps between contexts
1144 	//
1145 	globalImages->BindNull();
1146 
1147 	qglFinish();
1148 	QE_CheckOpenGLForErrors();
1149 
1150 	if (!renderMode) {
1151 		// clean up any deffered tri's
1152 		R_ToggleSmpFrame();
1153 	}
1154 }
1155 
1156 /*
1157  =======================================================================================================================
1158  =======================================================================================================================
1159  */
OnSize(UINT nType,int cx,int cy)1160 void CCamWnd::OnSize(UINT nType, int cx, int cy) {
1161 	CWnd::OnSize(nType, cx, cy);
1162 
1163 	CRect	rect;
1164 	GetClientRect(rect);
1165 	m_Camera.width = rect.right;
1166 	m_Camera.height = rect.bottom;
1167 	InvalidateRect(NULL, false);
1168 }
1169 
1170 
1171 /*
1172  =======================================================================================================================
1173  =======================================================================================================================
1174  */
OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)1175 void CCamWnd::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) {
1176 	g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags, false);
1177 }
1178 
1179 //
1180 // =======================================================================================================================
1181 //    Timo brush primitive texture shifting, using camera view to select translations::
1182 // =======================================================================================================================
1183 //
ShiftTexture_BrushPrimit(face_t * f,int x,int y)1184 void CCamWnd::ShiftTexture_BrushPrimit(face_t *f, int x, int y) {
1185 /*
1186 	idVec3	texS, texT;
1187 	idVec3	viewX, viewY;
1188 	int		XS, XT, YS, YT;
1189 	int		outS, outT;
1190 #ifdef _DEBUG
1191 	if (!g_qeglobals.m_bBrushPrimitMode) {
1192 		common->Printf("Warning : unexpected call to CCamWnd::ShiftTexture_BrushPrimit with brush primitive mode disbaled\n");
1193 		return;
1194 	}
1195 #endif
1196 	// compute face axis base
1197 	//ComputeAxisBase(f->plane.Normal(), texS, texT);
1198 
1199 	// compute camera view vectors
1200 	VectorCopy(m_Camera.vup, viewY);
1201 	VectorCopy(m_Camera.vright, viewX);
1202 
1203 	// compute best vectors
1204 	//ComputeBest2DVector(viewX, texS, texT, XS, XT);
1205 	//ComputeBest2DVector(viewY, texS, texT, YS, YT);
1206 
1207 	// check this is not a degenerate case
1208 	if ((XS == YS) && (XT == YT))
1209 	{
1210 #ifdef _DEBUG
1211 		common->Printf("Warning : degenerate best vectors axis base in CCamWnd::ShiftTexture_BrushPrimit\n");
1212 #endif
1213 		// forget it
1214 		Select_ShiftTexture_BrushPrimit(f, x, y, false);
1215 		return;
1216 	}
1217 
1218 	// compute best fitted translation in face axis base
1219 	outS = XS * x + YS * y;
1220 	outT = XT * x + YT * y;
1221 
1222 	// call actual texture shifting code
1223 	Select_ShiftTexture_BrushPrimit(f, outS, outT, false);
1224 */
1225 }
1226 
1227 
IsBModel(brush_t * b)1228 bool IsBModel(brush_t *b) {
1229 	const char *v = ValueForKey( b->owner, "model" );
1230 	if (v && *v) {
1231 		const char *n = ValueForKey( b->owner, "name");
1232 		return (stricmp( n, v ) == 0);
1233 	}
1234 	return false;
1235 }
1236 
1237 /*
1238 ================
1239 BuildEntityRenderState
1240 
1241 Creates or updates modelDef and lightDef for an entity
1242 ================
1243 */
1244 int Brush_ToTris(brush_t *brush, idTriList *tris, idMatList *mats, bool models, bool bmodel);
1245 
BuildEntityRenderState(entity_t * ent,bool update)1246 void CCamWnd::BuildEntityRenderState( entity_t *ent, bool update) {
1247 	const char	*v;
1248 	idDict		spawnArgs;
1249 	const char	*name = NULL;
1250 
1251 	Entity_UpdateSoundEmitter( ent );
1252 
1253 	// delete the existing def if we aren't creating a brand new world
1254 	if ( !update ) {
1255 		if ( ent->lightDef >= 0 ) {
1256 			g_qeglobals.rw->FreeLightDef( ent->lightDef );
1257 			ent->lightDef = -1;
1258 		}
1259 
1260 		if ( ent->modelDef >= 0 ) {
1261 			g_qeglobals.rw->FreeEntityDef( ent->modelDef );
1262 			ent->modelDef = -1;
1263 		}
1264 	}
1265 
1266 	// if an entity doesn't have any brushes at all, don't do anything
1267 	if ( ent->brushes.onext == &ent->brushes ) {
1268 		return;
1269 	}
1270 
1271 	// if the brush isn't displayed (filtered or culled), don't do anything
1272 	if (FilterBrush(ent->brushes.onext)) {
1273 		return;
1274 	}
1275 
1276 	spawnArgs = ent->epairs;
1277 	if (ent->eclass->defArgs.FindKey("model")) {
1278 		spawnArgs.Set("model", ent->eclass->defArgs.GetString("model"));
1279 	}
1280 
1281 	// any entity can have a model
1282 	name = ValueForKey( ent, "name" );
1283 	v = spawnArgs.GetString("model");
1284 	if ( v && *v ) {
1285 		renderEntity_t	refent;
1286 
1287 		refent.referenceSound = ent->soundEmitter;
1288 
1289 		if ( !stricmp( name, v ) ) {
1290 			// build the model from brushes
1291 			idTriList tris(1024);
1292 			idMatList mats(1024);
1293 
1294 			for (brush_t *b = ent->brushes.onext; b != &ent->brushes; b = b->onext) {
1295 				Brush_ToTris( b, &tris, &mats, false, true);
1296 			}
1297 
1298 			if ( ent->modelDef >= 0 ) {
1299 				g_qeglobals.rw->FreeEntityDef( ent->modelDef );
1300 				ent->modelDef = -1;
1301 			}
1302 
1303 			idRenderModel *bmodel = renderModelManager->FindModel( name );
1304 
1305 			if ( bmodel ) {
1306 				renderModelManager->RemoveModel( bmodel );
1307 				renderModelManager->FreeModel( bmodel );
1308 			}
1309 
1310 			bmodel = renderModelManager->AllocModel();
1311 
1312 			bmodel->InitEmpty( name );
1313 
1314 			// add the surfaces to the renderModel
1315 			modelSurface_t	surf;
1316 			for ( int i = 0 ; i < tris.Num() ; i++ ) {
1317 				surf.geometry = tris[i];
1318 				surf.shader = mats[i];
1319 				bmodel->AddSurface( surf );
1320 			}
1321 
1322 			bmodel->FinishSurfaces();
1323 
1324 			renderModelManager->AddModel( bmodel );
1325 
1326 			// FIXME: brush entities
1327 			gameEdit->ParseSpawnArgsToRenderEntity( &spawnArgs, &refent );
1328 
1329 			ent->modelDef = g_qeglobals.rw->AddEntityDef( &refent );
1330 
1331 		} else {
1332 			// use the game's epair parsing code so
1333 			// we can use the same renderEntity generation
1334 			gameEdit->ParseSpawnArgsToRenderEntity( &spawnArgs, &refent );
1335 			idRenderModelMD5 *md5 = dynamic_cast<idRenderModelMD5 *>( refent.hModel );
1336 			if (md5) {
1337 				idStr str;
1338 				spawnArgs.GetString("anim", "idle", str);
1339 				refent.numJoints = md5->NumJoints();
1340 				if ( update && refent.joints ) {
1341 					Mem_Free16( refent.joints );
1342 				}
1343 				refent.joints = ( idJointMat * )Mem_Alloc16( refent.numJoints * sizeof( *refent.joints ) );
1344 				const idMD5Anim *anim = gameEdit->ANIM_GetAnimFromEntityDef(spawnArgs.GetString("classname"), str);
1345 				int frame = spawnArgs.GetInt("frame") + 1;
1346 				if ( frame < 1 ) {
1347 					frame = 1;
1348 				}
1349 				const idVec3 &offset = gameEdit->ANIM_GetModelOffsetFromEntityDef( spawnArgs.GetString("classname") );
1350 				gameEdit->ANIM_CreateAnimFrame( md5, anim, refent.numJoints, refent.joints, ( frame * 1000 ) / 24, offset, false );
1351 			}
1352 			if (ent->modelDef >= 0) {
1353 				g_qeglobals.rw->FreeEntityDef( ent->modelDef );
1354 			}
1355 			ent->modelDef = g_qeglobals.rw->AddEntityDef( &refent );
1356 		}
1357 	}
1358 
1359 	// check for lightdefs
1360 	if (!(ent->eclass->nShowFlags & ECLASS_LIGHT)) {
1361 		return;
1362 	}
1363 
1364 	if ( spawnArgs.GetBool( "start_off" ) ) {
1365 		return;
1366 	}
1367 	// use the game's epair parsing code so
1368 	// we can use the same renderLight generation
1369 
1370 	renderLight_t	lightParms;
1371 
1372 	gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &lightParms );
1373 	lightParms.referenceSound = ent->soundEmitter;
1374 
1375 	if (update && ent->lightDef >= 0) {
1376 		g_qeglobals.rw->UpdateLightDef( ent->lightDef, &lightParms );
1377 	} else {
1378 		if (ent->lightDef >= 0) {
1379 			g_qeglobals.rw->FreeLightDef(ent->lightDef);
1380 		}
1381 		ent->lightDef = g_qeglobals.rw->AddLightDef( &lightParms );
1382 	}
1383 
1384 }
1385 
Tris_ToOBJ(const char * outFile,idTriList * tris,idMatList * mats)1386 void Tris_ToOBJ(const char *outFile, idTriList *tris, idMatList *mats) {
1387 	idFile *f = fileSystem->OpenExplicitFileWrite( outFile );
1388 	if ( f ) {
1389 		char out[1024];
1390 		strcpy(out, outFile);
1391 		StripExtension(out);
1392 
1393 		idList<idStr*> matNames;
1394 		int i, j, k;
1395 		int indexBase = 1;
1396 		idStr lastMaterial("");
1397 		int matCount = 0;
1398 		//idStr basePath = cvarSystem->GetCVarString( "fs_savepath" );
1399 		f->Printf( "mtllib %s.mtl\n", out );
1400 		for (i = 0; i < tris->Num(); i++) {
1401 			srfTriangles_t *tri = (*tris)[i];
1402 			for (j = 0; j < tri->numVerts; j++) {
1403 				f->Printf( "v %f %f %f\n", tri->verts[j].xyz.x, tri->verts[j].xyz.z, -tri->verts[j].xyz.y );
1404 			}
1405 			for (j = 0; j < tri->numVerts; j++) {
1406 				f->Printf( "vt %f %f\n", tri->verts[j].st.x, 1.0f - tri->verts[j].st.y );
1407 			}
1408 			for (j = 0; j < tri->numVerts; j++) {
1409 				f->Printf( "vn %f %f %f\n", tri->verts[j].normal.x, tri->verts[j].normal.y, tri->verts[j].normal.z );
1410 			}
1411 
1412 			if (stricmp( (*mats)[i]->GetName(), lastMaterial)) {
1413 				lastMaterial = (*mats)[i]->GetName();
1414 
1415 				bool found = false;
1416 				for (k = 0; k < matNames.Num(); k++) {
1417 					if ( idStr::Icmp(matNames[k]->c_str(), lastMaterial.c_str()) == 0 ) {
1418 						found = true;
1419 						// f->Printf( "usemtl m%i\n", k );
1420 						f->Printf( "usemtl %s\n", lastMaterial.c_str() );
1421 						break;
1422 					}
1423 				}
1424 
1425 				if (!found) {
1426 					// f->Printf( "usemtl m%i\n", matCount++ );
1427 					f->Printf( "usemtl %s\n", lastMaterial.c_str() );
1428 					matNames.Append(new idStr(lastMaterial));
1429 				}
1430 			}
1431 
1432 			for (int j = 0; j < tri->numIndexes; j += 3) {
1433 				int i1, i2, i3;
1434 				i1 = tri->indexes[j+2] + indexBase;
1435 				i2 = tri->indexes[j+1] + indexBase;
1436 				i3 = tri->indexes[j] + indexBase;
1437 				f->Printf( "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i1,i1,i1, i2,i2,i2, i3,i3,i3 );
1438 			}
1439 
1440 			indexBase += tri->numVerts;
1441 
1442 		}
1443 		fileSystem->CloseFile( f );
1444 
1445 		strcat(out, ".mtl");
1446 		f = fileSystem->OpenExplicitFileWrite( out );
1447 		if (f) {
1448 			for (k = 0; k < matNames.Num(); k++) {
1449 				// This presumes the diffuse tga name matches the material name
1450 				f->Printf( "newmtl %s\n\tNs 0\n\td 1\n\tillum 2\n\tKd 0 0 0 \n\tKs 0.22 0.22 0.22 \n\tKa 0 0 0 \n\tmap_Kd %s/base/%s.tga\n\n\n", matNames[k]->c_str(), "z:/d3xp", matNames[k]->c_str() );
1451 			}
1452 			fileSystem->CloseFile( f );
1453 		}
1454 
1455 	}
1456 }
1457 
Brush_TransformModel(brush_t * brush,idTriList * tris,idMatList * mats)1458 int Brush_TransformModel(brush_t *brush, idTriList *tris, idMatList *mats) {
1459 	int ret = 0;
1460 	if (brush->modelHandle > 0 ) {
1461 		idRenderModel *model = brush->modelHandle;
1462 		if (model) {
1463 			float	a = FloatForKey(brush->owner, "angle");
1464 			float	s, c;
1465 			//FIXME: support full rotation matrix
1466 			bool matrix = false;
1467 			if (a) {
1468 				s = sin( DEG2RAD(a) );
1469 				c = cos( DEG2RAD(a) );
1470 			}
1471 			idMat3 mat;
1472 			if (GetMatrixForKey(brush->owner, "rotation", mat)) {
1473 				matrix = true;
1474 			}
1475 
1476 
1477 			for (int i = 0; i < model->NumSurfaces() ; i++) {
1478 				const modelSurface_t	*surf = model->Surface( i );
1479 				srfTriangles_t	*tri = surf->geometry;
1480 				srfTriangles_t *tri2 = R_CopyStaticTriSurf(tri);
1481 				for (int j = 0; j < tri2->numVerts; j++) {
1482 					idVec3	v;
1483 					if (matrix) {
1484 						v = tri2->verts[j].xyz * brush->owner->rotation + brush->owner->origin;
1485 					} else {
1486 						v = tri2->verts[j].xyz;
1487 						VectorAdd(v, brush->owner->origin, v);
1488 						float x = v[0];
1489 						float y = v[1];
1490 						if (a) {
1491 							float	x2 = (((x - brush->owner->origin[0]) * c) - ((y - brush->owner->origin[1]) * s)) + brush->owner->origin[0];
1492 							float	y2 = (((x - brush->owner->origin[0]) * s) + ((y - brush->owner->origin[1]) * c)) + brush->owner->origin[1];
1493 							x = x2;
1494 							y = y2;
1495 						}
1496 						v[0] = x;
1497 						v[1] = y;
1498 					}
1499 					tri2->verts[j].xyz = v;
1500 				}
1501 				tris->Append(tri2);
1502 				mats->Append( surf->shader );
1503 			}
1504 			return model->NumSurfaces();
1505 		}
1506 	}
1507 	return ret;
1508 }
1509 
1510 
1511 #define	MAX_TRI_SURFACES	16384
Brush_ToTris(brush_t * brush,idTriList * tris,idMatList * mats,bool models,bool bmodel)1512 int Brush_ToTris(brush_t *brush, idTriList *tris, idMatList *mats, bool models, bool bmodel) {
1513 	int i, j;
1514 	srfTriangles_t	*tri;
1515 	//
1516 	// patches
1517 	//
1518 	if (brush->modelHandle > 0 ) {
1519 		if (!models) {
1520 			return 0;
1521 		} else {
1522 			return Brush_TransformModel(brush, tris, mats);
1523 		}
1524 	}
1525 
1526 	int numSurfaces = 0;
1527 
1528 	if ( brush->owner->eclass->fixedsize && !brush->entityModel) {
1529 		return NULL;
1530 	}
1531 
1532 	if ( brush->pPatch ) {
1533 		patchMesh_t *pm;
1534 		int			width, height;
1535 
1536 		pm = brush->pPatch;
1537 
1538 		// build a patch mesh
1539 		idSurface_Patch *cp = new idSurface_Patch( pm->width * 6, pm->height * 6 );
1540 		cp->SetSize( pm->width, pm->height );
1541 		for ( i = 0; i < pm->width; i++ ) {
1542 			for ( j = 0; j < pm->height; j++ ) {
1543 				(*cp)[j*cp->GetWidth()+i].xyz =  pm->ctrl(i, j).xyz;
1544 				(*cp)[j*cp->GetWidth()+i].st = pm->ctrl(i, j).st;
1545 			}
1546 		}
1547 
1548 		// subdivide it
1549 		if ( pm->explicitSubdivisions ) {
1550 			cp->SubdivideExplicit( pm->horzSubdivisions, pm->vertSubdivisions, true );
1551 		} else {
1552 			cp->Subdivide( DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_LENGTH, true );
1553 		}
1554 		width = cp->GetWidth();
1555 		height = cp->GetHeight();
1556 
1557 		// convert to srfTriangles
1558 		tri = R_AllocStaticTriSurf();
1559 		tri->numVerts = width * height;
1560 		tri->numIndexes = 6 * ( width - 1 ) * ( height - 1 );
1561 		R_AllocStaticTriSurfVerts( tri, tri->numVerts );
1562 		R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
1563 		for ( i = 0 ; i < tri->numVerts ; i++ ) {
1564 			tri->verts[i] = (*cp)[i];
1565 			if (bmodel) {
1566 				tri->verts[i].xyz -= brush->owner->origin;
1567 			}
1568 		}
1569 
1570 		tri->numIndexes = 0;
1571 		for ( i = 1 ; i < width ; i++ ) {
1572 			for ( j = 1 ; j < height ; j++ ) {
1573 				tri->indexes[tri->numIndexes++] = ( j - 1 ) * width + i;
1574 				tri->indexes[tri->numIndexes++] = ( j - 1 ) * width + i - 1;
1575 				tri->indexes[tri->numIndexes++] = j * width + i - 1;
1576 
1577 				tri->indexes[tri->numIndexes++] = j * width + i;
1578 				tri->indexes[tri->numIndexes++] = ( j - 1 ) * width + i;
1579 				tri->indexes[tri->numIndexes++] = j * width + i - 1;
1580 			}
1581 		}
1582 
1583 		delete cp;
1584 
1585 		tris->Append(tri);
1586 		mats->Append(pm->d_texture);
1587 		//surfaces[numSurfaces] = tri;
1588 		//materials[numSurfaces] = pm->d_texture;
1589 		return 1;
1590 	}
1591 
1592 	//
1593 	// normal brush
1594 	//
1595 	for ( face_t *face = brush->brush_faces ; face; face = face->next ) {
1596 		idWinding *w;
1597 
1598 		w = face->face_winding;
1599 		if (!w) {
1600 			continue;	// freed or degenerate face
1601 		}
1602 
1603 		tri = R_AllocStaticTriSurf();
1604 		tri->numVerts = w->GetNumPoints();
1605 		tri->numIndexes = ( w->GetNumPoints() - 2 ) * 3;
1606 		R_AllocStaticTriSurfVerts( tri, tri->numVerts );
1607 		R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
1608 
1609 		for ( i = 0 ; i < tri->numVerts ; i++ ) {
1610 
1611 			tri->verts[i].Clear();
1612 
1613 			tri->verts[i].xyz[0] = (*w)[i][0];
1614 			tri->verts[i].xyz[1] = (*w)[i][1];
1615 			tri->verts[i].xyz[2] = (*w)[i][2];
1616 
1617 			if ( bmodel ) {
1618 				tri->verts[i].xyz -= brush->owner->origin;
1619 			}
1620 
1621 			tri->verts[i].st[0] = (*w)[i][3];
1622 			tri->verts[i].st[1] = (*w)[i][4];
1623 
1624 			tri->verts[i].normal = face->plane.Normal();
1625 		}
1626 
1627 		tri->numIndexes = 0;
1628 		for ( i = 2 ; i < w->GetNumPoints() ; i++ ) {
1629 			tri->indexes[tri->numIndexes++] = 0;
1630 			tri->indexes[tri->numIndexes++] = i-1;
1631 			tri->indexes[tri->numIndexes++] = i;
1632 		}
1633 
1634 		tris->Append(tri);
1635 		mats->Append(face->d_texture);
1636 		numSurfaces++;
1637 	}
1638 
1639 	return numSurfaces;
1640 }
1641 
Select_ToOBJ()1642 void Select_ToOBJ() {
1643 	int i;
1644 	CFileDialog dlgFile(FALSE, "obj", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Wavefront object files (*.obj)|*.obj||", g_pParentWnd);
1645 	if (dlgFile.DoModal() == IDOK) {
1646 		idTriList tris(1024);
1647 		idMatList mats(1024);
1648 
1649 		for (brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) {
1650 
1651 			if ( b->hiddenBrush ) {
1652 				continue;
1653 			}
1654 
1655 			if (FilterBrush(b)) {
1656 				continue;
1657 			}
1658 
1659 			Brush_ToTris(b, &tris, &mats, true, false);
1660 		}
1661 
1662 		Tris_ToOBJ(dlgFile.GetPathName().GetBuffer(0), &tris, &mats);
1663 
1664 		for( i = 0; i < tris.Num(); i++ ) {
1665 			R_FreeStaticTriSurf( tris[i] );
1666 		}
1667 		tris.Clear();
1668 	}
1669 }
1670 
Select_ToCM()1671 void Select_ToCM() {
1672 	CFileDialog dlgFile( FALSE, "lwo, ase", NULL, 0, "(*.lwo)|*.lwo|(*.ase)|*.ase|(*.ma)|*.ma||", g_pParentWnd );
1673 
1674 	if ( dlgFile.DoModal() == IDOK ) {
1675 		idMapEntity *mapEnt;
1676 		idMapPrimitive *p;
1677 		idStr name;
1678 
1679 		name = fileSystem->OSPathToRelativePath( dlgFile.GetPathName() );
1680 		name.BackSlashesToSlashes();
1681 
1682 		mapEnt = new idMapEntity();
1683 		mapEnt->epairs.Set( "name", name.c_str() );
1684 
1685 		for ( brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next ) {
1686 
1687 			if ( b->hiddenBrush ) {
1688 				continue;
1689 			}
1690 
1691 			if ( FilterBrush( b ) ) {
1692 				continue;
1693 			}
1694 
1695 			p = BrushToMapPrimitive( b, b->owner->origin );
1696 			if ( p ) {
1697 				mapEnt->AddPrimitive( p );
1698 			}
1699 		}
1700 
1701 		collisionModelManager->WriteCollisionModelForMapEntity( mapEnt, name.c_str() );
1702 
1703 		delete mapEnt;
1704 	}
1705 }
1706 
1707 
1708 /*
1709 =================
1710 BuildRendererState
1711 
1712 Builds models, lightdefs, and modeldefs for the current editor data
1713 so it can be rendered by the game renderSystem
1714 =================
1715 */
BuildRendererState()1716 void CCamWnd::BuildRendererState() {
1717 	renderEntity_t	worldEntity;
1718 	entity_t	*ent;
1719 	brush_t		*brush;
1720 
1721 	FreeRendererState();
1722 
1723 	// the renderWorld holds all the references and defs
1724 	g_qeglobals.rw->InitFromMap( NULL );
1725 
1726 	// create the raw model for all the brushes
1727 	int numBrushes = 0;
1728 	int numSurfaces = 0;
1729 
1730 	// the renderModel for the world holds all the geometry that isn't in an entity
1731 	worldModel = renderModelManager->AllocModel();
1732 	worldModel->InitEmpty( "EditorWorldModel" );
1733 
1734 	for ( brush_t *brushList = &active_brushes ; brushList ;
1735 		brushList = (brushList == &active_brushes) ? &selected_brushes : NULL ) {
1736 
1737 		for (brush = brushList->next; brush != brushList; brush = brush->next) {
1738 
1739 			if ( brush->hiddenBrush ) {
1740 				continue;
1741 			}
1742 
1743 			if (FilterBrush(brush)) {
1744 				continue;
1745 			}
1746 
1747 			if (CullBrush(brush, true)) {
1748 				continue;
1749 			}
1750 
1751 			idTriList tris(1024);
1752 			idMatList mats(1024);
1753 
1754 			if (!IsBModel(brush)) {
1755 				numSurfaces += Brush_ToTris( brush, &tris, &mats, false, false );
1756 			}
1757 
1758 			// add the surfaces to the renderModel
1759 			modelSurface_t	surf;
1760 			for ( int i = 0 ; i < tris.Num() ; i++ ) {
1761 				surf.geometry = tris[i];
1762 				surf.shader = mats[i];
1763 				worldModel->AddSurface( surf );
1764 			}
1765 
1766 			numBrushes++;
1767 		}
1768 	}
1769 
1770 	// bound and clean the triangles
1771 	worldModel->FinishSurfaces();
1772 
1773 	// the worldEntity just has the handle for the worldModel
1774 	memset( &worldEntity, 0, sizeof( worldEntity ) );
1775 	worldEntity.hModel = worldModel;
1776 	worldEntity.axis = mat3_default;
1777 	worldEntity.shaderParms[0] = 1;
1778 	worldEntity.shaderParms[1] = 1;
1779 	worldEntity.shaderParms[2] = 1;
1780 	worldEntity.shaderParms[3] = 1;
1781 
1782 	worldModelDef = g_qeglobals.rw->AddEntityDef( &worldEntity );
1783 
1784 	// create the light and model entities exactly the way the game code would
1785 	for ( ent = entities.next ; ent != &entities ; ent = ent->next ) {
1786 		if ( ent->brushes.onext == &ent->brushes ) {
1787 			continue;
1788 		}
1789 
1790 		if (CullBrush(ent->brushes.onext, true)) {
1791 			continue;
1792 		}
1793 
1794 		if (Map_IsBrushFiltered(ent->brushes.onext)) {
1795 			continue;
1796 		}
1797 
1798 		BuildEntityRenderState( ent, false );
1799 	}
1800 
1801 	//common->Printf("Render data used %d brushes\n", numBrushes);
1802 	worldDirty = false;
1803 	UpdateCaption();
1804 }
1805 
1806 /*
1807 ===============================
1808 CCamWnd::UpdateRenderEntities
1809 
1810   Creates a new entity state list
1811   returns true if a repaint is needed
1812 ===============================
1813 */
UpdateRenderEntities()1814 bool CCamWnd::UpdateRenderEntities() {
1815 
1816 	if (rebuildMode) {
1817 		return false;
1818 	}
1819 
1820 	bool ret = false;
1821 	for ( entity_t *ent = entities.next ; ent != &entities ; ent = ent->next ) {
1822 		BuildEntityRenderState( ent, (ent->lightDef != -1 || ent->modelDef != -1 || ent->soundEmitter ) ? true : false );
1823 		if (ret == false && ent->modelDef || ent->lightDef) {
1824 			ret = true;
1825 		}
1826 	}
1827 	return ret;
1828 }
1829 
1830 /*
1831 ============================
1832 CCamWnd::FreeRendererState
1833 
1834   Frees the render state data
1835 ============================
1836 */
FreeRendererState()1837 void CCamWnd::FreeRendererState() {
1838 
1839 	for ( entity_t *ent = entities.next ; ent != &entities ; ent = ent->next ) {
1840 		if (ent->lightDef >= 0) {
1841 			g_qeglobals.rw->FreeLightDef( ent->lightDef );
1842 			ent->lightDef = -1;
1843 		}
1844 
1845 		if (ent->modelDef >= 0) {
1846 			renderEntity_t *refent = const_cast<renderEntity_t *>(g_qeglobals.rw->GetRenderEntity( ent->modelDef ));
1847 			if ( refent ) {
1848 				if ( refent->callbackData ) {
1849 					Mem_Free( refent->callbackData );
1850 					refent->callbackData = NULL;
1851 				}
1852 				if ( refent->joints ) {
1853 					Mem_Free16(refent->joints);
1854 					refent->joints = NULL;
1855 				}
1856 			}
1857 			g_qeglobals.rw->FreeEntityDef( ent->modelDef );
1858 			ent->modelDef = -1;
1859 		}
1860 	}
1861 
1862 	if ( worldModel ) {
1863 		renderModelManager->FreeModel( worldModel );
1864 		worldModel = NULL;
1865 	}
1866 
1867 }
1868 
1869 
1870 /*
1871 ========================
1872 CCamWnd::UpdateCaption
1873 
1874   updates the caption based on rendermode and whether the render mode needs updated
1875 ========================
1876 */
UpdateCaption()1877 void CCamWnd::UpdateCaption() {
1878 
1879 	idStr strCaption;
1880 
1881 	if (worldDirty) {
1882 		strCaption = "*";
1883 	}
1884 	// FIXME:
1885 	strCaption += (renderMode) ? "RENDER" : "CAM";
1886 	if (renderMode) {
1887 		strCaption += (rebuildMode) ? " (Realtime)" : "";
1888 		strCaption += (entityMode) ? " +lights" : "";
1889 		strCaption += (selectMode) ? " +selected" : "";
1890 		strCaption += (animationMode) ? " +anim" : "";
1891 	}
1892 	strCaption += (soundMode) ? " +snd" : "";
1893 	SetWindowText(strCaption);
1894 }
1895 
1896 /*
1897 ===========================
1898 CCamWnd::ToggleRenderMode
1899 
1900 	Toggles the render mode
1901 ===========================
1902 */
ToggleRenderMode()1903 void CCamWnd::ToggleRenderMode() {
1904 	renderMode ^= 1;
1905 	UpdateCaption();
1906 }
1907 
1908 /*
1909 ===========================
1910 CCamWnd::ToggleRebuildMode
1911 
1912 	Toggles the rebuild mode
1913 ===========================
1914 */
ToggleRebuildMode()1915 void CCamWnd::ToggleRebuildMode() {
1916 	rebuildMode ^= 1;
1917 	UpdateCaption();
1918 }
1919 
1920 /*
1921 ===========================
1922 CCamWnd::ToggleEntityMode
1923 
1924 	Toggles the entity mode
1925 ===========================
1926 */
ToggleEntityMode()1927 void CCamWnd::ToggleEntityMode() {
1928 	entityMode ^= 1;
1929 	UpdateCaption();
1930 }
1931 
1932 
1933 /*
1934 ===========================
1935 CCamWnd::ToggleRenderMode
1936 
1937 	Toggles the render mode
1938 ===========================
1939 */
ToggleAnimationMode()1940 void CCamWnd::ToggleAnimationMode() {
1941 	animationMode ^= 1;
1942 	if (animationMode)  {
1943 		SetTimer(0, 10, NULL);
1944 	} else {
1945 		KillTimer(0);
1946 	}
1947 	UpdateCaption();
1948 }
1949 
1950 /*
1951 ===========================
1952 CCamWnd::ToggleSoundMode
1953 
1954 	Toggles the sound mode
1955 ===========================
1956 */
ToggleSoundMode()1957 void CCamWnd::ToggleSoundMode() {
1958 	soundMode ^= 1;
1959 
1960 	UpdateCaption();
1961 
1962 	for ( entity_t *ent = entities.next ; ent != &entities ; ent = ent->next ) {
1963 		Entity_UpdateSoundEmitter( ent );
1964 	}
1965 }
1966 
1967 /*
1968 ===========================
1969 CCamWnd::ToggleRenderMode
1970 
1971 	Toggles the render mode
1972 ===========================
1973 */
ToggleSelectMode()1974 void CCamWnd::ToggleSelectMode() {
1975 	selectMode ^= 1;
1976 	UpdateCaption();
1977 }
1978 
1979 /*
1980 =========================
1981 CCamWnd::MarkWorldDirty
1982 
1983   marks the render world as dirty
1984 =========================
1985 */
MarkWorldDirty()1986 void CCamWnd::MarkWorldDirty() {
1987 	worldDirty = true;
1988 	UpdateCaption();
1989 }
1990 
1991 
1992 /*
1993 =========================
1994 CCamWnd::DrawEntityData
1995 
1996   Draws entity data ( experimental )
1997 =========================
1998 */
1999 extern void glBox(idVec4 &color, idVec3 &point, float size);
2000 
DrawEntityData()2001 void CCamWnd::DrawEntityData() {
2002 
2003 	qglMatrixMode( GL_MODELVIEW );
2004 	qglLoadIdentity();
2005 	qglMatrixMode( GL_PROJECTION );
2006 	qglLoadIdentity();
2007 
2008 	SetProjectionMatrix();
2009 
2010 	qglRotatef(-90, 1, 0, 0);	// put Z going up
2011 	qglRotatef(90, 0, 0, 1);	// put Z going up
2012 	qglRotatef(m_Camera.angles[0], 0, 1, 0);
2013 	qglRotatef(-m_Camera.angles[1], 0, 0, 1);
2014 	qglTranslatef(-m_Camera.origin[0], -m_Camera.origin[1], -m_Camera.origin[2]);
2015 
2016 	Cam_BuildMatrix();
2017 
2018 	if (!(entityMode || selectMode)) {
2019 		return;
2020 	}
2021 
2022 	qglDisable(GL_BLEND);
2023 	qglDisable(GL_DEPTH_TEST);
2024 	qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2025 	globalImages->BindNull();
2026 	idVec3 color(0, 1, 0);
2027 	qglColor3fv( color.ToFloatPtr() );
2028 
2029 	brush_t *brushList = &active_brushes;
2030 	int pass = 0;
2031 	while (brushList) {
2032 		for (brush_t *brush = brushList->next; brush != brushList; brush = brush->next) {
2033 
2034 			if (CullBrush(brush, true)) {
2035 				continue;
2036 			}
2037 
2038 			if (FilterBrush(brush)) {
2039 				continue;
2040 			}
2041 
2042 			if ((pass == 1 && selectMode) || (entityMode && pass == 0 && brush->owner->lightDef >= 0)) {
2043 				Brush_DrawXY(brush, 0, true, true);
2044 			}
2045 
2046 		}
2047 		brushList = (brushList == &active_brushes) ? &selected_brushes : NULL;
2048 		color.x = 1;
2049 		color.y = 0;
2050 		pass++;
2051 		qglColor3fv( color.ToFloatPtr() );
2052 	}
2053 
2054 }
2055 
2056 
2057 /*
2058  =======================================================================================================================
2059 	Cam_Render
2060 
2061 	This used the renderSystem to draw a fully lit view of the world
2062  =======================================================================================================================
2063  */
Cam_Render()2064 void CCamWnd::Cam_Render() {
2065 
2066 	renderView_t	refdef;
2067 	CPaintDC	dc(this);	// device context for painting
2068 
2069 
2070 	if (!active_brushes.next) {
2071 		return;					// not valid yet
2072 	}
2073 
2074 	// DG: from SteelStorm2
2075 	// Jmarshal23 recommended to disable this to fix lighting render in the Cam window
2076 	/* if (!qwglMakeCurrent(dc.m_hDC, win32.hGLRC)) {
2077 		common->Printf("ERROR: wglMakeCurrent failed..\n ");
2078 		common->Printf("Please restart " EDITOR_WINDOWTEXT " if the camera view is not working\n");
2079 		return;
2080 	} */
2081 
2082 	// save the editor state
2083 	//qglPushAttrib( GL_ALL_ATTRIB_BITS );
2084 	qglClearColor( 0.1f, 0.1f, 0.1f, 0.0f );
2085 	qglScissor( 0, 0, m_Camera.width, m_Camera.height );
2086 	qglClear( GL_COLOR_BUFFER_BIT );
2087 
2088 	//	qwglSwapBuffers(dc.m_hDC);
2089 
2090 	// create the model, using explicit normals
2091 	if ( rebuildMode && worldDirty ) {
2092 		BuildRendererState();
2093 	}
2094 
2095 	// render it
2096 	renderSystem->BeginFrame( m_Camera.width, m_Camera.height );
2097 
2098 	memset( &refdef, 0, sizeof( refdef ) );
2099 	refdef.vieworg = m_Camera.origin;
2100 
2101 	// the editor uses opposite pitch convention
2102 	refdef.viewaxis = idAngles( -m_Camera.angles.pitch, m_Camera.angles.yaw, m_Camera.angles.roll ).ToMat3();
2103 
2104 	refdef.width = SCREEN_WIDTH;
2105 	refdef.height = SCREEN_HEIGHT;
2106 	refdef.fov_x = 90;
2107 	refdef.fov_y = 2 * atan((float)m_Camera.height / m_Camera.width) * idMath::M_RAD2DEG;
2108 
2109 	// only set in animation mode to give a consistent look
2110 	if (animationMode) {
2111 		refdef.time = eventLoop->Milliseconds();
2112 	}
2113 
2114 	g_qeglobals.rw->RenderScene( &refdef );
2115 
2116 	int	frontEnd, backEnd;
2117 
2118 	renderSystem->EndFrame( &frontEnd, &backEnd );
2119 //common->Printf( "front:%i back:%i\n", frontEnd, backEnd );
2120 
2121 	//qglPopAttrib();
2122 	//DrawEntityData();
2123 
2124 	//qwglSwapBuffers(dc.m_hDC);
2125 	// get back to the editor state
2126 	qglMatrixMode( GL_MODELVIEW );
2127 	qglLoadIdentity();
2128 	Cam_BuildMatrix();
2129 }
2130 
2131 
OnTimer(UINT nIDEvent)2132 void CCamWnd::OnTimer(UINT nIDEvent)
2133 {
2134 	if (animationMode || nIDEvent == 1) {
2135 		Sys_UpdateWindows(W_CAMERA);
2136 	}
2137 	if (nIDEvent == 1) {
2138 		KillTimer(1);
2139 	}
2140 
2141 	if (!animationMode ) {
2142 		KillTimer(0);
2143 	}
2144 }
2145 
2146 
UpdateCameraView()2147 void CCamWnd::UpdateCameraView() {
2148 	if (QE_SingleBrush(true, true)) {
2149 		brush_t *b = selected_brushes.next;
2150 		if (b->owner->eclass->nShowFlags & ECLASS_CAMERAVIEW) {
2151 			// find the entity that targets this
2152 			const char *name = ValueForKey(b->owner, "name");
2153 			entity_t *ent = FindEntity("target", name);
2154 			if (ent) {
2155 				if (!saveValid) {
2156 					saveOrg = m_Camera.origin;
2157 					saveAng = m_Camera.angles;
2158 					saveValid = true;
2159 				}
2160 				idVec3 v = b->owner->origin - ent->origin;
2161 				v.Normalize();
2162 				idAngles ang = v.ToMat3().ToAngles();
2163 				ang.pitch = -ang.pitch;
2164 				ang.roll = 0.0f;
2165 				SetView( ent->origin, ang );
2166 				Cam_BuildMatrix();
2167 				Sys_UpdateWindows( W_CAMERA );
2168 				return;
2169 			}
2170 		}
2171 	}
2172 	if (saveValid) {
2173 		SetView(saveOrg, saveAng);
2174 		Cam_BuildMatrix();
2175 		Sys_UpdateWindows(W_CAMERA);
2176 		saveValid = false;
2177 	}
2178 }
2179