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