apply back 335 and 336, will need to update deps and put a zip out
[xonotic/netradiant.git] / radiant / camwindow.cpp
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 //
23 // Camera Window
24 //
25 // Leonardo Zide (leo@lokigames.com)
26 //
27
28 #include "stdafx.h"
29 #include <gtk/gtk.h>
30 #include <GL/gl.h>
31
32 extern void DrawPathLines();
33 extern void Select_ShiftTexture(int x, int y);
34 extern void Select_RotateTexture(int amt);
35 extern void DrawAlternatePoint(vec3_t v, float scale);
36 //extern void Select_ScaleTexture(int x, int y);
37
38 extern int g_nPatchClickedView;
39
40 brush_t* g_pSplitList = NULL;
41
42 // =============================================================================
43 // CamWnd class
44
45 CamWnd::CamWnd ()
46   : GLWindow (TRUE), m_XORRectangle(m_pWidget)
47 {
48   m_nNumTransBrushes = 0;
49   memset(&m_Camera, 0, sizeof(camera_t));
50   m_pSide_select = NULL;
51   m_bClipMode = false;
52   m_bFreeMove = false;
53   Cam_Init();
54 }
55
56 CamWnd::~CamWnd ()
57 {
58 }
59
60 void CamWnd::OnCreate ()
61 {
62   if (!MakeCurrent ())
63     Error ("glMakeCurrent failed");
64
65   // report OpenGL information
66   Sys_Printf ("GL_VENDOR: %s\n", qglGetString (GL_VENDOR));
67   Sys_Printf ("GL_RENDERER: %s\n", qglGetString (GL_RENDERER));
68   Sys_Printf ("GL_VERSION: %s\n", qglGetString (GL_VERSION));
69   Sys_Printf ("GL_EXTENSIONS: %s\n", qglGetString (GL_EXTENSIONS));
70
71   // Set off texture compression supported
72   g_qeglobals.bTextureCompressionSupported = 0;
73
74   // finalize OpenGL init
75   // NOTE
76   // why is this here? well .. the Gtk objects get constructed when you enter gtk_main
77   // and I wanted to have the extensions information in the editor startup console (avoid looking that up in the early console)
78   // RIANT
79   // I Split this up so as to add support for extension and user-friendly
80   // compression format selection.
81   // ADD new globals for your new format so as to minimise
82   // calls to Sys_QGL_ExtensionSupported
83   // NOTE TTimo: I don't really like this approach with globals. Frequent calls to Sys_QGL_ExtensionSupported don't sound like
84   //   a problem to me. If there is some caching to be done, then I think it should be inside Sys_QGL_ExtensionSupported
85   ///////////////////////////////////////////
86   // Check for default OpenGL
87   if (Sys_QGL_ExtensionSupported ("GL_ARB_texture_compression"))
88   {
89     g_qeglobals.bTextureCompressionSupported = 1;
90     g_qeglobals.m_bOpenGLCompressionSupported = 1;
91   }
92
93   // INSERT PROPRIETARY EXTENSIONS HERE
94   // Check for S3 extensions
95   // create a bool global for extension supported
96   if (Sys_QGL_ExtensionSupported ("GL_EXT_texture_compression_s3tc"))
97   {
98     g_qeglobals.bTextureCompressionSupported = 1;
99     g_qeglobals.m_bS3CompressionSupported = 1;
100   }
101
102   g_qeglobals.m_bOpenGLReady = true;
103
104   g_PrefsDlg.UpdateTextureCompression();
105
106 #ifdef ATIHACK_812
107   g_PrefsDlg.UpdateATIHack();
108 #endif
109
110   g_qeglobals_gui.d_camera = m_pWidget;
111 }
112
113 void CamWnd::Cam_Init ()
114 {
115   m_Camera.timing = false;
116   m_Camera.origin[0] = 0.f;
117   m_Camera.origin[1] = 20.f;
118   m_Camera.origin[2] = 46.f;
119   m_Camera.color[0] = 0.3f;
120   m_Camera.color[1] = 0.3f;
121   m_Camera.color[2] = 0.3f;
122   m_nCambuttonstate = 0;
123 }
124
125 void CamWnd::OnSize(int cx, int cy)
126 {
127   m_Camera.width = cx;
128   m_Camera.height = cy;
129   gtk_widget_queue_draw(m_pWidget);
130 }
131
132 rectangle_t rectangle_from_area_cam()
133 {
134   const float left = MIN(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0]);
135   const float top = MAX(g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1]);
136   const float right = MAX(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0]);
137   const float bottom = MIN(g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1]);
138   return rectangle_t(left, bottom, right - left, top - bottom);
139 }
140
141 void update_xor_rectangle(XORRectangle& xor_rectangle)
142 {
143   rectangle_t rectangle;
144         if ((g_qeglobals.d_select_mode == sel_area))
145     rectangle = rectangle_from_area_cam();
146   xor_rectangle.set(rectangle);
147 }
148
149 void CamWnd::OnMouseMove(guint32 flags, int pointx, int pointy)
150 {
151   int height = m_pWidget->allocation.height;
152   // NOTE RR2DO2 this hasn't got any use anymore really. It is an old qeradiant feature
153   // that can be re-enabled by removing the checks for HasCapture and not shift/ctrl down
154   // but the scaling/rotating (unless done with the steps set in the surface inspector
155   // dialog) is way too sensitive to be of any use
156   if (HasCapture () && Sys_AltDown () &&
157       !((flags & MK_SHIFT) || (flags & MK_CONTROL)))
158   {
159     if (flags & MK_CONTROL)
160       Select_RotateTexture(pointy - m_ptLastCursorY);
161     else
162     if (flags & MK_SHIFT)
163       Select_ScaleTexture(pointx - m_ptLastCursorX, m_ptLastCursorY - pointy);
164     else
165       Select_ShiftTexture(pointx - m_ptLastCursorX, m_ptLastCursorY - pointy);
166   }
167   else
168   {
169     Cam_MouseMoved(pointx, height - 1 - pointy, flags);
170   }
171   m_ptLastCursorX = pointx;
172   m_ptLastCursorY = pointy;
173
174   update_xor_rectangle(m_XORRectangle);
175 }
176
177 void CamWnd::OnMouseWheel(bool bUp)
178 {
179   if (bUp)
180     VectorMA (m_Camera.origin, g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin);
181   else
182     VectorMA (m_Camera.origin, -g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin);
183
184   int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA);
185   Sys_UpdateWindows (nUpdate);
186   g_pParentWnd->OnTimer ();
187 }
188
189 void CamWnd::OnLButtonDown(guint32 nFlags, int pointx, int pointy)
190 {
191   m_ptLastCursorX = pointx;
192   m_ptLastCursorY = pointy;
193   OriginalMouseDown(nFlags, pointx, pointy);
194 }
195
196 void CamWnd::OnLButtonUp(guint32 nFlags, int pointx, int pointy)
197 {
198   OriginalMouseUp(nFlags, pointx, pointy);
199 }
200
201 void CamWnd::OnMButtonDown(guint32 nFlags, int pointx, int pointy)
202 {
203   OriginalMouseDown(nFlags, pointx, pointy);
204 }
205
206 void CamWnd::OnMButtonUp(guint32 nFlags, int pointx, int pointy)
207 {
208   OriginalMouseUp(nFlags, pointx, pointy);
209 }
210
211 void CamWnd::OnRButtonDown(guint32 nFlags, int pointx, int pointy)
212 {
213   OriginalMouseDown(nFlags, pointx, pointy);
214 }
215
216 void CamWnd::OnRButtonUp(guint32 nFlags, int pointx, int pointy)
217 {
218   OriginalMouseUp(nFlags, pointx, pointy);
219 }
220
221 void CamWnd::OriginalMouseUp(guint32 nFlags, int pointx, int pointy)
222 {
223   int height = m_pWidget->allocation.height;
224
225   if(g_qeglobals.d_select_mode == sel_facets_on || g_qeglobals.d_select_mode == sel_facets_off)
226   {
227     g_qeglobals.d_select_mode = sel_brush;
228   }
229
230   Cam_MouseUp(pointx, height - 1 - pointy, nFlags);
231   ReleaseCapture ();
232
233   update_xor_rectangle(m_XORRectangle);
234 }
235
236 void CamWnd::OriginalMouseDown(guint32 nFlags, int pointx, int pointy)
237 {
238   int height = m_pWidget->allocation.height;
239
240   SetFocus();
241   SetCapture();
242   Cam_MouseDown (pointx, height - 1 - pointy, nFlags);
243
244   update_xor_rectangle(m_XORRectangle);
245 }
246
247 void CamWnd::Cam_BuildMatrix()
248 {
249   float ya;
250   float matrix[4][4];
251   int           i;
252
253   if (!m_bFreeMove)
254   {
255     ya = m_Camera.angles[1]/180*Q_PI;
256
257     // the movement matrix is kept 2d
258     m_Camera.forward[0] = cos(ya);
259     m_Camera.forward[1] = sin(ya);
260     m_Camera.forward[2] = 0;
261     m_Camera.right[0] = m_Camera.forward[1];
262     m_Camera.right[1] = -m_Camera.forward[0];
263   }
264   else
265   {
266     AngleVectors( m_Camera.angles, m_Camera.forward, m_Camera.right, NULL );
267     m_Camera.forward[2] = -m_Camera.forward[2];
268   }
269
270   memcpy(matrix, m_Camera.projection, sizeof(m4x4_t));
271   m4x4_multiply_by_m4x4(&matrix[0][0], &m_Camera.modelview[0][0]);
272
273   //qglGetFloatv (GL_PROJECTION_MATRIX, &matrix[0][0]);
274
275   for (i=0 ; i<3 ; i++)
276   {
277     m_Camera.vright[i] = matrix[i][0];
278     m_Camera.vup[i] = matrix[i][1];
279     m_Camera.vpn[i] = matrix[i][2];
280   }
281
282   VectorNormalize (m_Camera.vright, m_Camera.vright);
283   VectorNormalize (m_Camera.vup, m_Camera.vup);
284   VectorNormalize (m_Camera.vpn, m_Camera.vpn);
285 }
286
287 void CamWnd::Cam_ChangeFloor (qboolean up)
288 {
289   brush_t       *b;
290   float d, bestd, current;
291   vec3_t        start, dir;
292
293   start[0] = m_Camera.origin[0];
294   start[1] = m_Camera.origin[1];
295   start[2] = g_MaxWorldCoord;
296   dir[0] = dir[1] = 0;
297   dir[2] = -1;
298
299   current = g_MaxWorldCoord - (m_Camera.origin[2] - 48);
300   if (up)
301     bestd = 0;
302   else
303     bestd = 2*g_MaxWorldCoord;
304
305   for (b=active_brushes.next ; b != &active_brushes ; b=b->next)
306   {
307     if (!Brush_Ray (start, dir, b, &d))
308       continue;
309     if (up && d < current && d > bestd)
310       bestd = d;
311     if (!up && d > current && d < bestd)
312       bestd = d;
313   }
314
315   if (bestd == 0 || bestd == 2*g_MaxWorldCoord)
316     return;
317
318   m_Camera.origin[2] += current - bestd;
319   Sys_UpdateWindows (W_CAMERA|W_Z_OVERLAY);
320 }
321
322 void CamWnd::Cam_PositionDrag()
323 {
324   int x, y;
325
326   Sys_GetCursorPos (&x, &y);
327   if (x != m_ptCursorX || y != m_ptCursorY)
328   {
329     x -= m_ptCursorX;
330     VectorMA (m_Camera.origin, x, m_Camera.vright, m_Camera.origin);
331     y -= m_ptCursorY;
332     m_Camera.origin[2] -= y;
333     Sys_SetCursorPos(m_ptCursorX, m_ptCursorY);
334     Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY);
335   }
336 }
337
338 void CamWnd::Cam_MouseControl (float dtime)
339 {
340   Cam_KeyControl (dtime);
341
342   if( g_PrefsDlg.m_bCamFreeLook )
343   {
344     int dx, dy;
345     gint x, y;
346
347     if( !m_bFreeMove || m_nCambuttonstate == MK_CONTROL )
348       return;
349
350     // Update angles
351     Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY);
352
353     dx = m_ptLastCamCursorX - m_ptCursorX;
354     dy = m_ptLastCamCursorY - m_ptCursorY;
355
356     gdk_window_get_origin( m_pWidget->window, &x, &y);
357
358     m_ptLastCamCursorX = x + (m_Camera.width / 2);
359     m_ptLastCamCursorY = y + (m_Camera.height / 2);
360
361     Sys_SetCursorPos(m_ptLastCamCursorX, m_ptLastCamCursorY);
362
363     // Don't use pitch
364     if(!g_PrefsDlg.m_bCamFreeLookStrafe) {
365       if (g_PrefsDlg.m_bCamInverseMouse)
366             m_Camera.angles[PITCH] -= dy * dtime * g_PrefsDlg.m_nAngleSpeed;
367       else
368             m_Camera.angles[PITCH] += dy * dtime * g_PrefsDlg.m_nAngleSpeed;
369     } else {
370       VectorMA (m_Camera.origin, dy * (float) (g_PrefsDlg.m_nMoveSpeed / 6.0f), m_Camera.forward, m_Camera.origin);
371     }
372
373     m_Camera.angles[YAW] += dx * dtime * g_PrefsDlg.m_nAngleSpeed;
374
375     if (m_Camera.angles[PITCH] > 90)
376       m_Camera.angles[PITCH] = 90;
377     else if (m_Camera.angles[PITCH] < -90)
378       m_Camera.angles[PITCH] = -90;
379
380     if (m_Camera.angles[YAW] >= 360)
381       m_Camera.angles[YAW] = 0;
382     else if (m_Camera.angles[YAW] <= -360)
383       m_Camera.angles[YAW] = 0;
384
385     if( dx || dy || m_Camera.movementflags )
386     {
387       int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA);
388       Sys_UpdateWindows (nUpdate);
389       g_pParentWnd->OnTimer ();
390     }
391   }
392   else
393   {
394     int   xl, xh;
395     int yl, yh;
396     float       xf, yf;
397
398     if (g_PrefsDlg.m_nMouseButtons == 2)
399     {
400       if (m_nCambuttonstate != (MK_RBUTTON | MK_SHIFT))
401         return;
402     }
403     else
404     {
405       if (m_nCambuttonstate != MK_RBUTTON)
406         return;
407     }
408
409     xf = (float)(m_ptButtonX - m_Camera.width/2) / (m_Camera.width/2);
410     yf = (float)(m_ptButtonY - m_Camera.height/2) / (m_Camera.height/2);
411
412     xl = m_Camera.width/3;
413     xh = xl*2;
414     yl = m_Camera.height/3;
415     yh = yl*2;
416
417     xf *= 1.0 - fabs(yf);
418     if (xf < 0)
419     {
420       xf += 0.1f;
421       if (xf > 0)
422         xf = 0;
423     }
424     else
425     {
426       xf -= 0.1f;
427       if (xf < 0)
428         xf = 0;
429     }
430
431     VectorMA (m_Camera.origin, yf*dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin);
432     m_Camera.angles[YAW] += xf*-dtime*g_PrefsDlg.m_nAngleSpeed;
433
434     int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA);
435     Sys_UpdateWindows (nUpdate);
436     g_pParentWnd->OnTimer ();
437   }
438 }
439
440 void CamWnd::Cam_KeyControl (float dtime) {
441
442   // Update angles
443   if (m_Camera.movementflags & MOVE_ROTLEFT)
444     m_Camera.angles[YAW] += 15*dtime*g_PrefsDlg.m_nAngleSpeed;
445   if (m_Camera.movementflags & MOVE_ROTRIGHT)
446     m_Camera.angles[YAW] -= 15*dtime*g_PrefsDlg.m_nAngleSpeed;
447
448   // Update position
449   if (m_Camera.movementflags & MOVE_FORWARD)
450     VectorMA (m_Camera.origin, dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin);
451   if (m_Camera.movementflags & MOVE_BACK)
452     VectorMA (m_Camera.origin, -dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin);
453   if (m_Camera.movementflags & MOVE_STRAFELEFT)
454     VectorMA (m_Camera.origin, -dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.right, m_Camera.origin);
455   if (m_Camera.movementflags & MOVE_STRAFERIGHT)
456     VectorMA (m_Camera.origin, dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.right, m_Camera.origin);
457
458   // Save a screen update (when m_bFreeMove is enabled, mousecontrol does the update)
459   if( !m_bFreeMove && m_Camera.movementflags )
460   {
461      int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA);
462      Sys_UpdateWindows (nUpdate);
463      g_pParentWnd->OnTimer ();
464   }
465 }
466
467 // NOTE TTimo if there's an OS-level focus out of the application
468 //   then we can release the camera cursor grab
469 static gint camwindow_focusout(GtkWidget* widget, GdkEventKey* event, gpointer data)
470 {
471   g_pParentWnd->GetCamWnd ()->ToggleFreeMove();
472   return FALSE;
473 }
474
475 void CamWnd::ToggleFreeMove()
476 {
477   GdkWindow *window;
478   GtkWidget *widget;
479
480   m_bFreeMove = !m_bFreeMove;
481   Camera()->movementflags = 0;
482   m_ptLastCamCursorX = m_ptCursorX;
483   m_ptLastCamCursorY = m_ptCursorY;
484
485   if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating)
486   {
487     widget = g_pParentWnd->GetCamWnd ()->m_pParent;
488     window = widget->window;
489   }
490   else
491   {
492     widget = g_pParentWnd->m_pWidget;
493     window = widget->window;
494   }
495
496   if (m_bFreeMove)
497   {
498
499     SetFocus();
500     SetCapture();
501
502     {
503       GdkPixmap *pixmap;
504       GdkBitmap *mask;
505       char buffer [(32 * 32)/8];
506       memset (buffer, 0, (32 * 32)/8);
507       GdkColor white = {0, 0xffff, 0xffff, 0xffff};
508       GdkColor black = {0, 0x0000, 0x0000, 0x0000};
509       pixmap = gdk_bitmap_create_from_data (NULL, buffer, 32, 32);
510       mask   = gdk_bitmap_create_from_data (NULL, buffer, 32, 32);
511       GdkCursor *cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &white, &black, 1, 1);
512
513       gdk_window_set_cursor (window, cursor);
514       gdk_cursor_unref (cursor);
515       gdk_drawable_unref (pixmap);
516       gdk_drawable_unref (mask);
517     }
518
519     // RR2DO2: FIXME why does this only work the 2nd and
520     // further times the event is called? (floating windows
521     // mode seems to work fine though...)
522     m_FocusOutHandler_id = gtk_signal_connect (GTK_OBJECT (widget), "focus_out_event",
523                       GTK_SIGNAL_FUNC (camwindow_focusout), g_pParentWnd);
524
525     {
526       GdkEventMask mask = (GdkEventMask)(GDK_POINTER_MOTION_MASK
527       | GDK_POINTER_MOTION_HINT_MASK
528       | GDK_BUTTON_MOTION_MASK
529       | GDK_BUTTON1_MOTION_MASK
530       | GDK_BUTTON2_MOTION_MASK
531       | GDK_BUTTON3_MOTION_MASK
532       | GDK_BUTTON_PRESS_MASK
533       | GDK_BUTTON_RELEASE_MASK);
534
535       gdk_pointer_grab(widget->window, TRUE, mask, widget->window, NULL, GDK_CURRENT_TIME);
536     }
537   }
538   else
539   {
540     gdk_pointer_ungrab(GDK_CURRENT_TIME);
541
542     gtk_signal_disconnect (GTK_OBJECT (widget), m_FocusOutHandler_id);
543
544     GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR);
545     gdk_window_set_cursor (window, cursor);
546     gdk_cursor_unref (cursor);
547
548     ReleaseCapture();
549   }
550
551   int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA);
552   Sys_UpdateWindows (nUpdate);
553   g_pParentWnd->OnTimer ();
554 }
555
556 void CamWnd::Cam_MouseDown(int x, int y, int buttons)
557 {
558   vec3_t  dir;
559   float   f, r, u;
560   int     i;
561
562
563   //
564   // calc ray direction
565   //
566   u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f );
567   r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f );
568   f = 1;
569
570   for (i=0 ; i<3 ; i++)
571     dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u;
572   VectorNormalize (dir, dir);
573
574   Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY);
575
576   m_nCambuttonstate = buttons;
577   m_ptButtonX = x;
578   m_ptButtonY = y;
579
580   // LBUTTON = manipulate selection
581   // shift-LBUTTON = select
582   // middle button = grab texture
583   // ctrl-middle button = set entire brush to texture
584   // ctrl-shift-middle button = set single face to texture
585   int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
586   if ((buttons == MK_LBUTTON)
587       || (buttons == (MK_LBUTTON | MK_SHIFT))
588       || (buttons == (MK_LBUTTON | MK_CONTROL))
589       || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT))
590       || (buttons == nMouseButton)
591       || (buttons == (nMouseButton|MK_SHIFT))
592       || (buttons == (nMouseButton|MK_CONTROL))
593       || (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL)))
594   {
595     if (g_PrefsDlg.m_nMouseButtons == 2 && (buttons == (MK_RBUTTON | MK_SHIFT)))
596     {
597       if (g_PrefsDlg.m_bCamFreeLook)
598         ToggleFreeMove();
599       else
600         Cam_MouseControl (0.1f);
601     }
602     else
603     {
604       // something global needs to track which window is responsible for stuff
605       Patch_SetView(W_CAMERA);
606       Drag_Begin (x, y, buttons, m_Camera.vright, m_Camera.vup, m_Camera.origin, dir, true);
607     }
608     return;
609   }
610
611   if (buttons == MK_RBUTTON)
612   {
613     if (g_PrefsDlg.m_bCamFreeLook)
614       ToggleFreeMove();
615     else
616       Cam_MouseControl (0.1f);
617     return;
618   }
619 }
620
621 void CamWnd::Cam_MouseUp (int x, int y, int buttons)
622 {
623   m_nCambuttonstate = 0;
624   Drag_MouseUp (buttons);
625 }
626
627 void CamWnd::Cam_MouseMoved (int x, int y, int buttons)
628 {
629   m_nCambuttonstate = buttons;
630   if (!buttons)
631     return;
632
633   if( g_PrefsDlg.m_nCamDragMultiSelect )
634   {
635     if (g_qeglobals.d_select_mode == sel_brush_on  || g_qeglobals.d_select_mode == sel_brush_off)
636     {
637       bool bDoDragMultiSelect = FALSE;
638
639       if( g_PrefsDlg.m_nCamDragMultiSelect == 1 && buttons == (MK_LBUTTON|MK_SHIFT) )
640         bDoDragMultiSelect = TRUE;
641       else if( g_PrefsDlg.m_nCamDragMultiSelect == 2 && buttons == (MK_LBUTTON|MK_CONTROL) && Sys_AltDown() )
642         bDoDragMultiSelect = TRUE;
643
644       if( bDoDragMultiSelect )
645       {
646         vec3_t  dir;
647         float   f, r, u;
648         int     i;
649
650         //
651         // calc ray direction
652         //
653         u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f );
654         r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f );
655         f = 1;
656
657         for (i=0 ; i<3 ; i++)
658           dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u;
659         VectorNormalize (dir,dir);
660
661         switch( g_qeglobals.d_select_mode )
662         {
663         case sel_brush_on:
664           Select_Ray( m_Camera.origin, dir, (SF_DRAG_ON|SF_CAMERA) );
665           break;
666
667         case sel_brush_off:
668           Select_Ray( m_Camera.origin, dir, (SF_DRAG_OFF|SF_CAMERA) );
669           break;
670
671         default:
672           break;
673         }
674         return;
675       }
676     }
677     else if (g_qeglobals.d_select_mode == sel_facets_on || g_qeglobals.d_select_mode == sel_facets_off)
678     {
679       if( buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) )
680       {
681         vec3_t dir;
682         float           f, r, u;
683         int                     i;
684
685         //
686         // calc ray direction
687         //
688         u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f );
689         r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f );
690         f = 1;
691
692         for (i=0 ; i<3 ; i++)
693           dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u;
694         VectorNormalize (dir,dir);
695
696         switch( g_qeglobals.d_select_mode )
697         {
698         case sel_facets_on:
699           Select_Ray( m_Camera.origin, dir, (SF_SINGLEFACE|SF_DRAG_ON|SF_CAMERA) );
700           break;
701
702         case sel_facets_off:
703           Select_Ray( m_Camera.origin, dir, (SF_SINGLEFACE|SF_DRAG_OFF|SF_CAMERA) );
704           break;
705
706         default:
707           break;
708         }
709         return;
710       }
711     }
712   }
713
714   m_ptButtonX = x;
715   m_ptButtonY = y;
716
717   if ( (m_bFreeMove && (buttons & MK_CONTROL) && !(buttons & MK_SHIFT)) || (!m_bFreeMove && (buttons == (MK_RBUTTON|MK_CONTROL))) )
718   {
719     Cam_PositionDrag ();
720     Sys_UpdateWindows (W_XY|W_CAMERA|W_Z);
721     return;
722   }
723
724   Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY);
725
726   if (buttons & (MK_LBUTTON | MK_MBUTTON) )
727   {
728     Drag_MouseMoved (x, y, buttons);
729     if(g_qeglobals.d_select_mode != sel_area)
730       Sys_UpdateWindows (W_XY|W_CAMERA|W_Z);
731   }
732 }
733
734 void CamWnd::InitCull()
735 {
736   int i;
737
738   VectorSubtract (m_Camera.vpn, m_Camera.vright, m_vCull1);
739   VectorAdd (m_Camera.vpn, m_Camera.vright, m_vCull2);
740
741   for (i=0 ; i<3 ; i++)
742   {
743     if (m_vCull1[i] > 0)
744       m_nCullv1[i] = 3+i;
745     else
746       m_nCullv1[i] = i;
747     if (m_vCull2[i] > 0)
748       m_nCullv2[i] = 3+i;
749     else
750       m_nCullv2[i] = i;
751   }
752 }
753
754 qboolean CamWnd::CullBrush (brush_t *b)
755 {
756   int    i;
757   vec3_t point;
758   float  d;
759
760   if (g_PrefsDlg.m_bCubicClipping)
761   {
762     float fLevel = g_PrefsDlg.m_nCubicScale * 64;
763
764     point[0] = m_Camera.origin[0] - fLevel;
765     point[1] = m_Camera.origin[1] - fLevel;
766     point[2] = m_Camera.origin[2] - fLevel;
767
768     for (i=0; i<3; i++)
769       if (b->mins[i] < point[i] && b->maxs[i] < point[i])
770         return true;
771
772     point[0] = m_Camera.origin[0] + fLevel;
773     point[1] = m_Camera.origin[1] + fLevel;
774     point[2] = m_Camera.origin[2] + fLevel;
775
776     for (i=0; i<3; i++)
777       if (b->mins[i] > point[i] && b->maxs[i] > point[i])
778         return true;
779   }
780
781   for (i=0 ; i<3 ; i++)
782     point[i] = b->mins[m_nCullv1[i]] - m_Camera.origin[i];
783
784   d = DotProduct (point, m_vCull1);
785   if (d < -1)
786     return true;
787
788   for (i=0 ; i<3 ; i++)
789     point[i] = b->mins[m_nCullv2[i]] - m_Camera.origin[i];
790
791   d = DotProduct (point, m_vCull2);
792   if (d < -1)
793     return true;
794
795   return false;
796 }
797
798 // project a 3D point onto the camera space
799 // we use the GL viewing matrixes
800 // this is the implementation of a glu function (I realized that afterwards): gluProject
801 void CamWnd::ProjectCamera(const vec3_t A, vec_t B[2])
802 {
803
804   vec_t P1[4],P2[4],P3[4];
805   VectorCopy(A,P1); P1[3] = 1;
806
807   GLMatMul(m_Camera.modelview , P1, P2);
808   GLMatMul(m_Camera.projection, P2, P3);
809
810   // we ASSUME that the view port is 0 0 m_Camera.width m_Camera.height (you can check in Cam_Draw)
811   B[0] = (float)m_Camera.width  * ( P3[0] + 1.0 ) / 2.0;
812   B[1] = (float)m_Camera.height * ( P3[1] + 1.0 ) / 2.0;
813
814 }
815
816 // vec defines a direction in geometric space and P an origin point
817 // the user is interacting from the camera view
818 // (for example with texture adjustment shortcuts)
819 // and intuitively if he hits left / right / up / down
820 //   what happens in geometric space should match the left/right/up/down move in camera space
821 // axis = 0: vec is along left/right
822 // axis = 1: vec is along up/down
823 // sgn = +1: same directions
824 // sgn = -1: opposite directions
825 // Implementation:
826 //   typical use case is giving a face center and a normalized vector
827 //   1) compute start and endpoint, project them in camera view, get the direction
828 //     depending on the situation, we might bump into precision issues with that
829 //   2) possible to compute the projected direction independently?
830 //     this solution would be better but right now I don't see how to do it..
831 void CamWnd::MatchViewAxes(const vec3_t P, const vec3_t vec, int &axis, float &sgn)
832 {
833
834   vec_t A[2],B[2],V[2];
835   ProjectCamera(P,A);
836   vec3_t Q;
837   VectorAdd(P,vec,Q);
838   ProjectCamera(Q,B);
839   // V is the vector projected in camera space
840   V[0] = B[0] - A[0];
841   V[1] = B[1] - A[1];
842   if (fabs(V[0])>fabs(V[1]))
843   {
844     // best match is against right
845     axis = 0;
846     if (V[0]>0)
847       sgn = +1;
848     else
849       sgn = -1;
850   }
851   else
852   {
853     // best match is against up
854     axis = 1;
855     if (V[1]>0)
856       sgn = +1;
857     else
858       sgn = -1;
859   }
860 }
861
862 #if 0
863 void CamWnd::DrawLightRadius(brush_t* pBrush)
864 {
865   // if lighting
866   int nRadius = Brush_LightRadius(pBrush);
867   if (nRadius > 0)
868   {
869     Brush_SetLightColor(pBrush);
870           qglEnable (GL_BLEND);
871           qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
872           qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
873           qglDisable (GL_TEXTURE_2D);
874
875     qglEnable(GL_TEXTURE_2D);
876     qglDisable(GL_BLEND);
877     qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
878   }
879 }
880 #endif
881
882 extern void DrawPatchMesh(patchMesh_t *pm);
883 extern void DrawPatchControls(patchMesh_t *pm);
884 extern void Brush_DrawFacingAngle (brush_t *b, entity_t *e);
885 extern void Brush_DrawModel(brush_t *b, bool bTextured = false);
886 extern void DrawModelOrigin(brush_t *b);
887 extern void DrawModelBBox(brush_t *b);
888
889 void CamWnd::Cam_DrawBrush(brush_t *b, int mode)
890 {
891   int nGLState = m_Camera.draw_glstate;
892   int nModelMode = g_PrefsDlg.m_nEntityShowState;
893
894         GLfloat material[4], identity[4];
895         VectorSet(identity, 0.8f, 0.8f, 0.8f);
896         IShader *pShader;
897
898   // lights
899   if (b->owner->eclass->fixedsize && b->owner->eclass->nShowFlags & ECLASS_LIGHT && g_PrefsDlg.m_bNewLightDraw)
900   {
901                 switch (mode)
902                 {
903                 case DRAW_SOLID:
904                   VectorCopy(b->owner->color, material);
905                         VectorScale(material, 0.8f, material);
906       material[3] = 1.0f;
907
908       qglColor4fv(material);
909
910       if (g_PrefsDlg.m_bNewLightDraw)
911         DrawLight(b->owner, nGLState, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, 0);
912
913                         break;
914                 }
915   }
916
917   // models
918   else if(b->owner->eclass->fixedsize && b->owner->model.pRender
919     && !(!IsBrushSelected(b) && (nModelMode & ENTITY_SELECTED_ONLY)))
920   {
921     switch (mode)
922                 {
923                 case DRAW_TEXTURED:
924                         if (!(nModelMode & ENTITY_WIREFRAME) && nModelMode != ENTITY_BOX)
925                         {
926                                 VectorCopy(b->owner->eclass->color, material);
927                                 material[3] = identity[3] = 1.0f;
928
929                                 qglEnable(GL_CULL_FACE);
930
931                                 if(!(nGLState & DRAW_GL_TEXTURE_2D)) qglColor4fv(material);
932         else qglColor4fv(identity);
933                                 if(nGLState & DRAW_GL_LIGHTING) qglShadeModel(GL_SMOOTH);
934
935                                 b->owner->model.pRender->Draw(nGLState, DRAW_RF_CAM);
936                         }
937                         break;
938                 case DRAW_WIRE:
939       VectorCopy(b->owner->eclass->color, material);
940                   material[3] = 1.0f;
941                   qglColor4fv(material);
942
943                         // model view mode "wireframe" or "selected wire"
944                         if(nModelMode & ENTITY_WIREFRAME)
945                                 b->owner->model.pRender->Draw(nGLState, DRAW_RF_CAM);
946
947                         // model view mode "skinned and boxed"
948       if(!(b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) )
949       {
950                     qglColor4fv(material);
951         aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE);
952       }
953       else if(nModelMode & ENTITY_BOXED)
954       {
955                                 aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE);
956       }
957 /*
958       if(!(nModelMode & ENTITY_BOXED) && b->owner->eclass->nShowFlags & ECLASS_MISCMODEL)
959                           DrawModelOrigin(b);
960 */
961                 }
962   }
963
964   // patches
965   else if (b->patchBrush)
966   {
967                 bool bTrans = (b->pPatch->pShader->getTrans() < 1.0f);
968                 switch(mode)
969                 {
970                 case DRAW_TEXTURED:
971                         if (!g_bPatchWireFrame && ((nGLState & DRAW_GL_BLEND && bTrans) || (!(nGLState & DRAW_GL_BLEND) && !bTrans)))
972                         {
973                                 qglDisable(GL_CULL_FACE);
974
975                                 pShader = b->pPatch->pShader;
976         VectorCopy(pShader->getTexture()->color, material);
977                                 material[3] = identity[3] = pShader->getTrans();
978
979         if(nGLState & DRAW_GL_TEXTURE_2D) {
980           qglColor4fv(identity);
981                                         qglBindTexture(GL_TEXTURE_2D, pShader->getTexture()->texture_number);
982         }
983                                 else
984                                         qglColor4fv(material);
985                                 if(nGLState & DRAW_GL_LIGHTING) qglShadeModel(GL_SMOOTH);
986
987                                 DrawPatchMesh(b->pPatch);
988                         }
989                         break;
990                 case DRAW_WIRE:
991       if (g_bPatchWireFrame)
992       {
993         VectorCopy(b->pPatch->pShader->getTexture()->color, material);
994                                 material[3] = 1.0;
995         qglColor4fv(material);
996         DrawPatchMesh(b->pPatch);
997       }
998       if ( b->pPatch->bSelected && (g_qeglobals.d_select_mode == sel_curvepoint
999         || g_qeglobals.d_select_mode == sel_area
1000         || g_bPatchBendMode))
1001         DrawPatchControls(b->pPatch);
1002     }
1003   }
1004
1005   // brushes
1006   else if(b->owner->eclass->fixedsize)
1007   {
1008                 switch(mode)
1009                 {
1010     case DRAW_SOLID:
1011                         VectorCopy(b->owner->eclass->color, material);
1012                         VectorScale(material, 0.8f, material);
1013       material[3] = 1.0f;
1014       qglColor4fv(material);
1015
1016                         qglEnable(GL_CULL_FACE);
1017                         qglShadeModel(GL_FLAT);
1018       Brush_Draw(b);
1019       break;
1020     case DRAW_WIRE:
1021                         if((g_qeglobals.d_savedinfo.include & INCLUDE_ANGLES)
1022       && (b->owner->eclass->nShowFlags & ECLASS_ANGLE))
1023                                 Brush_DrawFacingAngle(b, b->owner);
1024     }
1025   }
1026
1027   // brushes
1028   else
1029   {
1030                 switch(mode)
1031                 {
1032                 case DRAW_TEXTURED:
1033                         qglEnable(GL_CULL_FACE);
1034                         qglShadeModel(GL_FLAT);
1035       Brush_Draw(b);
1036     }
1037   }
1038 }
1039
1040 void CamWnd::Cam_DrawBrushes(int mode)
1041 {
1042   brush_t *b;
1043   brush_t *pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes;
1044
1045   for(b = active_brushes.next; b != &active_brushes; b=b->next)
1046     if (!b->bFiltered && !b->bCamCulled) Cam_DrawBrush(b, mode);
1047   for(b = pList->next; b != pList; b=b->next)
1048     if (!b->bFiltered && !b->bCamCulled) Cam_DrawBrush(b, mode);
1049 }
1050
1051 void CamWnd::Cam_DrawStuff()
1052 {
1053         GLfloat identity[4];
1054         VectorSet(identity, 0.8f, 0.8f, 0.8f);
1055         brush_t *b;
1056
1057   for(b = active_brushes.next; b != &active_brushes; b=b->next)
1058     b->bCamCulled = CullBrush(b);
1059
1060         for(b = selected_brushes.next; b != &selected_brushes; b=b->next)
1061     b->bCamCulled = CullBrush(b);
1062
1063         switch (m_Camera.draw_mode)
1064   {
1065   case cd_wire:
1066     qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
1067     qglDisable(GL_TEXTURE_2D);
1068     qglDisable(GL_TEXTURE_1D);
1069     qglDisable(GL_BLEND);
1070     qglEnable(GL_DEPTH_TEST);
1071                 qglEnableClientState(GL_VERTEX_ARRAY);
1072                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
1073                 qglShadeModel(GL_FLAT);
1074                 if(g_PrefsDlg.m_bGLLighting) {
1075       qglDisable(GL_LIGHTING);
1076                   qglDisable(GL_COLOR_MATERIAL);
1077                 qglDisableClientState(GL_NORMAL_ARRAY);
1078     }
1079                 m_Camera.draw_glstate = DRAW_GL_WIRE;
1080     break;
1081
1082   case cd_solid:
1083     qglCullFace(GL_FRONT);
1084     qglEnable(GL_CULL_FACE);
1085     qglShadeModel (GL_FLAT);
1086     qglPolygonMode (GL_FRONT, GL_LINE);
1087     qglPolygonMode (GL_BACK, GL_FILL);
1088     qglDisable(GL_TEXTURE_2D);
1089     qglDisable(GL_BLEND);
1090     qglEnable(GL_DEPTH_TEST);
1091                 qglEnableClientState(GL_VERTEX_ARRAY);
1092                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
1093                 qglPolygonOffset(-1.0, 2);
1094                 if(g_PrefsDlg.m_bGLLighting) {
1095       qglEnable(GL_LIGHTING);
1096                   qglEnable(GL_COLOR_MATERIAL);
1097 //    qglEnable(GL_RESCALE_NORMAL);
1098                   qglEnableClientState(GL_NORMAL_ARRAY);
1099     }
1100                 m_Camera.draw_glstate = DRAW_GL_SOLID;
1101     break;
1102
1103   case cd_texture:
1104     qglCullFace(GL_FRONT);
1105     qglEnable(GL_CULL_FACE);
1106     qglShadeModel (GL_FLAT);
1107     qglPolygonMode (GL_FRONT, GL_LINE);
1108     qglPolygonMode (GL_BACK, GL_FILL);
1109     qglEnable(GL_TEXTURE_2D);
1110     qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1111     qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1112     qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1113     qglDisable(GL_BLEND);
1114     qglEnable(GL_DEPTH_TEST);
1115                 qglEnableClientState(GL_VERTEX_ARRAY);
1116                 qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
1117                 if(g_PrefsDlg.m_bGLLighting) {
1118       qglEnable(GL_LIGHTING);
1119                   qglDisable(GL_COLOR_MATERIAL);
1120                   qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identity);
1121                   qglEnableClientState(GL_NORMAL_ARRAY);
1122 //    qglEnable(GL_RESCALE_NORMAL);
1123     }
1124                 qglPolygonOffset(-1.0, 2);
1125                 m_Camera.draw_glstate = DRAW_GL_TEXTURED;
1126     break;
1127
1128         default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n");
1129   }
1130
1131   Cam_DrawBrushes(DRAW_TEXTURED);
1132
1133         // setup for solid stuff
1134         switch(m_Camera.draw_mode)
1135         {
1136                 case cd_texture:
1137                         qglDisable(GL_TEXTURE_2D);
1138                         m_Camera.draw_glstate &= ~DRAW_GL_TEXTURE_2D;
1139                   if(g_PrefsDlg.m_bGLLighting)
1140                           qglEnable(GL_COLOR_MATERIAL);
1141                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
1142                         break;
1143                 case cd_solid:
1144                         break;
1145                 case cd_wire:
1146                         break;
1147                 default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n");
1148         }
1149
1150         qglEnable(GL_CULL_FACE);
1151         qglShadeModel(GL_FLAT);
1152         Cam_DrawBrushes(DRAW_SOLID);
1153
1154         // setup for wireframe stuff
1155         switch(m_Camera.draw_mode)
1156         {
1157                 case cd_texture:
1158       if(g_PrefsDlg.m_bGLLighting) {
1159                           qglDisable(GL_LIGHTING);
1160         qglDisable(GL_COLOR_MATERIAL);
1161                           qglDisableClientState(GL_NORMAL_ARRAY);
1162 //      qglDisable(GL_RESCALE_NORMAL);
1163       }
1164                         qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1165                         break;
1166                 case cd_solid:
1167       if(g_PrefsDlg.m_bGLLighting) {
1168         qglDisable(GL_LIGHTING);
1169                           qglDisable(GL_COLOR_MATERIAL);
1170                           qglDisableClientState(GL_NORMAL_ARRAY);
1171 //      qglDisable(GL_RESCALE_NORMAL);
1172       }
1173                         qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1174                         break;
1175                 case cd_wire:
1176                         break;
1177                 default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n");
1178         }
1179
1180   qglDisable(GL_CULL_FACE);
1181   Cam_DrawBrushes(DRAW_WIRE);
1182
1183         // setup for transparent texture stuff
1184         switch(m_Camera.draw_mode)
1185         {
1186                 case cd_texture:
1187                         qglPolygonMode (GL_FRONT, GL_LINE);
1188                         qglPolygonMode (GL_BACK, GL_FILL);
1189       if(g_PrefsDlg.m_bGLLighting) {
1190                           qglEnable(GL_COLOR_MATERIAL);
1191                           qglEnableClientState(GL_NORMAL_ARRAY);
1192                           qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identity);
1193       }
1194                         qglEnable(GL_TEXTURE_2D);
1195                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
1196                         m_Camera.draw_glstate = DRAW_GL_TEXTURED;
1197                         break;
1198                 case cd_solid:
1199                         qglPolygonMode (GL_FRONT, GL_LINE);
1200                         qglPolygonMode (GL_BACK, GL_FILL);
1201       if(g_PrefsDlg.m_bGLLighting) {
1202                           qglEnable(GL_LIGHTING);
1203                           qglEnable(GL_COLOR_MATERIAL);
1204                           qglEnableClientState(GL_NORMAL_ARRAY);
1205 //      qglEnable(GL_RESCALE_NORMAL);
1206       }
1207                         m_Camera.draw_glstate = DRAW_GL_SOLID;
1208                         break;
1209                 case cd_wire:
1210                         m_Camera.draw_glstate = DRAW_GL_WIRE;
1211                         break;
1212                 default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n");
1213         }
1214
1215
1216         qglEnable(GL_BLEND);
1217         m_Camera.draw_glstate |= DRAW_GL_BLEND;
1218   qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1219   // FIXME: some .TGA are buggy, have a completely empty alpha channel
1220   // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE
1221   // so I decided using GL_DECAL instead
1222   // if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent.
1223   // this could get better if you can get qglTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome
1224   // Arnout: empty alpha channels are now always filled with data. Don't set this anymore (would cause problems with qer_alphafunc too)
1225 //  qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
1226
1227         Cam_DrawBrushes(DRAW_TEXTURED);
1228
1229 //  qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1230   qglDisable(GL_BLEND);
1231
1232         // setup for wireframe stuff
1233         switch(m_Camera.draw_mode)
1234         {
1235                 case cd_texture:
1236       if(g_PrefsDlg.m_bGLLighting) {
1237                           qglDisable(GL_COLOR_MATERIAL);
1238         qglDisable(GL_LIGHTING);
1239 //      qglDisable(GL_RESCALE_NORMAL);
1240       }
1241                         break;
1242                 case cd_solid:
1243       if(g_PrefsDlg.m_bGLLighting) {
1244                           qglDisable(GL_COLOR_MATERIAL);
1245         qglDisable(GL_LIGHTING);
1246 //      qglDisable(GL_RESCALE_NORMAL);
1247       }
1248                         break;
1249                 case cd_wire:
1250                         break;
1251                 default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n");
1252         }
1253
1254 }
1255
1256 /*
1257 ==============
1258 Cam_Draw
1259 ==============
1260 */
1261
1262 void QueueClear ();
1263 void QueueDraw ();
1264
1265 void CamWnd::Cam_Draw()
1266 {
1267   brush_t       *brush;
1268   face_t        *face;
1269   float screenaspect;
1270   float yfov;
1271   double        start = 0.0, end;
1272   int           i;
1273
1274   if (!active_brushes.next)
1275     return;     // not valid yet
1276
1277   if (m_Camera.timing)
1278     start = Sys_DoubleTime ();
1279
1280   //
1281   // clear
1282   //
1283   QE_CheckOpenGLForErrors();
1284
1285   qglViewport(0, 0, m_Camera.width, m_Camera.height);
1286   qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0],
1287                  g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1],
1288                  g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], 0);
1289   qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1290
1291   //
1292   // set up viewpoint
1293   //
1294
1295
1296   qglMatrixMode(GL_PROJECTION);
1297   qglLoadIdentity ();
1298
1299   screenaspect = (float)m_Camera.width / m_Camera.height;
1300   yfov = 2*atan((float)m_Camera.height / m_Camera.width)*180/Q_PI;
1301   qgluPerspective (yfov,  screenaspect,  8,  32768);
1302
1303   // we're too lazy to calc projection matrix ourselves!!!
1304   qglGetFloatv (GL_PROJECTION_MATRIX, &m_Camera.projection[0][0]);
1305
1306   vec3_t vec;
1307
1308   m4x4_identity(&m_Camera.modelview[0][0]);
1309   VectorSet(vec, -90, 0, 0);
1310   m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ);
1311   VectorSet(vec, 0, 0, 90);
1312   m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ);
1313   VectorSet(vec, 0, m_Camera.angles[0], 0);
1314   m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ);
1315   VectorSet(vec, 0, 0, -m_Camera.angles[1]);
1316   m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ);
1317   VectorSet(vec, -m_Camera.origin[0],  -m_Camera.origin[1],  -m_Camera.origin[2]);
1318   m4x4_translate_by_vec3(&m_Camera.modelview[0][0], vec);
1319
1320   Cam_BuildMatrix ();
1321
1322   qglMatrixMode(GL_MODELVIEW);
1323   qglLoadIdentity();
1324
1325   qglMultMatrixf(&m_Camera.modelview[0][0]);
1326
1327   // grab the GL_PROJECTION and GL_MODELVIEW matrixes
1328   //   used in GetRelativeAxes
1329   //qglGetFloatv (GL_PROJECTION_MATRIX, &m_Camera.projection[0][0]);
1330   //qglGetFloatv (GL_MODELVIEW_MATRIX, &m_Camera.modelview[0][0]);
1331
1332 #if 0
1333   // TTimo: this is not used, just for verification (0, 0, m_Camera.width, m_Camera.height)
1334   GLint viewprt[4];
1335   qglGetIntegerv (GL_VIEWPORT, viewprt);
1336 #endif
1337
1338   if (g_PrefsDlg.m_bGLLighting)
1339   {
1340     GLfloat inverse_cam_dir[4], ambient[4], diffuse[4];//, material[4];
1341
1342     ambient[0] = ambient[1] = ambient[2] = 0.6f;
1343     ambient[3] = 1.0f;
1344     diffuse[0] = diffuse[1] = diffuse[2] = 0.4f;
1345     diffuse[3] = 1.0f;
1346     //material[0] = material[1] = material[2] = 0.8f;
1347     //material[3] = 1.0f;
1348
1349     vec3_t vCam, vRotate;
1350     VectorSet(vCam, -1, 0, 0); //default cam pos
1351     VectorSet(vRotate, 0, -m_Camera.angles[0], 0);
1352     VectorRotate(vCam, vRotate, vCam);
1353     VectorSet(vRotate, 0, 0, m_Camera.angles[1]);
1354     VectorRotate(vCam, vRotate, vCam);
1355
1356     inverse_cam_dir[0] = vCam[0];
1357     inverse_cam_dir[1] = vCam[1];
1358     inverse_cam_dir[2] = vCam[2];
1359     inverse_cam_dir[3] = 0;
1360
1361     qglColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
1362
1363     qglLightfv(GL_LIGHT0, GL_POSITION, inverse_cam_dir);
1364
1365     qglLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
1366     qglLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
1367
1368     qglEnable(GL_LIGHT0);
1369   }
1370
1371   InitCull ();
1372
1373   //
1374   // draw stuff
1375   //
1376
1377         Cam_DrawStuff();
1378
1379         qglEnableClientState(GL_VERTEX_ARRAY);
1380         qglDisableClientState(GL_NORMAL_ARRAY);
1381         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
1382         qglDisable (GL_TEXTURE_2D);
1383         qglDisable (GL_LIGHTING);
1384         qglDisable (GL_COLOR_MATERIAL);
1385
1386   qglEnable (GL_CULL_FACE);
1387
1388   brush_t* pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes;
1389
1390   if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL)
1391   {
1392     qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0], g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1], g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2], 0.3f);
1393     qglEnable (GL_BLEND);
1394     qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1395     qglDepthFunc (GL_LEQUAL);
1396     for (brush = pList->next ; brush != pList ; brush=brush->next)
1397     {
1398       if (brush->bCamCulled) // draw selected faces of filtered brushes to remind that there is a selection
1399         continue;
1400
1401       if (brush->patchBrush && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area))
1402         continue;
1403
1404       if (!g_PrefsDlg.m_bPatchBBoxSelect && brush->patchBrush)
1405       {
1406         DrawPatchMesh(brush->pPatch);
1407       }
1408       else if(brush->owner->model.pRender && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX)
1409       {
1410         brush->owner->model.pRender->Draw(DRAW_GL_FLAT, (DRAW_RF_SEL_OUTLINE|DRAW_RF_CAM));
1411       }
1412       else
1413       {
1414         for (face=brush->brush_faces ; face ; face=face->next)
1415           Brush_FaceDraw(face, DRAW_GL_FLAT);
1416       }
1417     }
1418
1419
1420     int nCount = g_ptrSelectedFaces.GetSize();
1421     if (nCount > 0)
1422     {
1423       for (int i = 0; i < nCount; i++)
1424       {
1425         face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i));
1426         Brush_FaceDraw(selFace, DRAW_GL_FLAT);
1427       }
1428     }
1429
1430     qglDisableClientState(GL_NORMAL_ARRAY);
1431           qglDepthFunc (GL_LESS);
1432   }
1433
1434   if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF)
1435   {
1436     // non-zbuffered outline
1437     qglDisable (GL_BLEND);
1438     qglDisable (GL_DEPTH_TEST);
1439     qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
1440     qglColor3f (1, 1, 1);
1441     for (brush = pList->next ; brush != pList ; brush=brush->next)
1442     {
1443       if ((brush->patchBrush && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area)))
1444         continue;
1445
1446       if (!g_PrefsDlg.m_bPatchBBoxSelect && brush->patchBrush)
1447       {
1448         DrawPatchMesh(brush->pPatch);
1449       }
1450       else if(brush->owner->model.pRender && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX)
1451       {
1452         brush->owner->model.pRender->Draw(DRAW_GL_WIRE, (DRAW_RF_SEL_FILL|DRAW_RF_CAM));
1453
1454         // Hydra : always draw bbox outline!
1455         aabb_draw(brush->owner->model.pRender->GetAABB(), DRAW_GL_WIRE);
1456       }
1457       else
1458       {
1459         for (face=brush->brush_faces ; face ; face=face->next)
1460           Brush_FaceDraw(face, DRAW_GL_WIRE);
1461       }
1462     }
1463   }
1464
1465   // edge / vertex flags
1466   if (g_qeglobals.d_select_mode == sel_vertex)
1467   {
1468     // GL_POINTS on Kyro Workaround
1469     if(!g_PrefsDlg.m_bGlPtWorkaround)
1470     {
1471       // brush verts
1472       qglPointSize (4);
1473                 qglColor3f (0,1,0);
1474       qglBegin (GL_POINTS);
1475         for (i=0 ; i<g_qeglobals.d_numpoints ; i++)
1476           qglVertex3fv (g_qeglobals.d_points[i]);
1477       qglEnd ();
1478
1479       if(g_qeglobals.d_num_move_points)
1480       {
1481         // selected brush verts
1482         qglPointSize (5);
1483         qglColor3f (0,0,1);
1484         qglBegin (GL_POINTS);
1485           for(i = 0; i < g_qeglobals.d_num_move_points; i++)
1486             qglVertex3fv (g_qeglobals.d_move_points[i]);
1487         qglEnd();
1488       }
1489
1490       qglPointSize (1);
1491     }
1492     else
1493     {
1494       // brush verts
1495       qglColor3f (0,1,0);
1496       qglLineWidth(2.0);
1497       qglBegin (GL_LINES);
1498         for (i=0; i < g_qeglobals.d_numpoints; i++)
1499           DrawAlternatePoint(g_qeglobals.d_points[i], 1.5);
1500       qglEnd();
1501
1502       if(g_qeglobals.d_num_move_points)
1503       {
1504         // selected brush verts
1505         qglColor3f (0,0,1);
1506         qglLineWidth (3.0);
1507         qglBegin (GL_LINES);
1508           for(i = 0; i < g_qeglobals.d_num_move_points; i++)
1509             qglVertex3fv (g_qeglobals.d_move_points[i]);
1510         qglEnd();
1511       }
1512       qglLineWidth(1.0);
1513     }
1514   }
1515   else if (g_qeglobals.d_select_mode == sel_edge)
1516   {
1517     float       *v1, *v2;
1518     // GL_POINTS on Kyro Workaround
1519     if(!g_PrefsDlg.m_bGlPtWorkaround)
1520     {
1521       qglPointSize (4);
1522       qglColor3f (0,0,1);
1523       qglBegin (GL_POINTS);
1524       for (i=0 ; i<g_qeglobals.d_numedges ; i++)
1525       {
1526         v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1];
1527         v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2];
1528         qglVertex3f ( (v1[0]+v2[0])*0.5,(v1[1]+v2[1])*0.5,(v1[2]+v2[2])*0.5);
1529       }
1530       qglEnd ();
1531       qglPointSize (1);
1532     }
1533     else {
1534       qglColor3f (0,0,1);
1535       qglLineWidth(2.0);
1536       qglBegin (GL_LINES);
1537       for (i=0; i < g_qeglobals.d_numedges; i++)
1538       {
1539         v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1];
1540         v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2];
1541         vec3_t v3;
1542         v3[0] = (v1[0]+v2[0])*0.5;
1543         v3[1] = (v1[1]+v2[1])*0.5;
1544         v3[2] = (v1[2]+v2[2])*0.5;
1545         DrawAlternatePoint(v3, 1.5);
1546       }
1547       qglEnd();
1548       qglLineWidth(1.0);
1549     }
1550   }
1551
1552   //
1553   // draw pointfile
1554   //
1555   qglEnable(GL_DEPTH_TEST);
1556   DrawPathLines();
1557
1558   if (g_qeglobals.d_pointfile_display_list)
1559   {
1560     Pointfile_Draw();
1561   }
1562
1563   // call the drawing routine of plugin entities
1564   //++timo FIXME: we might need to hook in other places as well for transparency etc.
1565   //++timo FIXME: also needs a way to get some parameters about the view
1566   //++timo FIXME: maybe provide some culling API on Radiant side?
1567   Draw3DPluginEntities();
1568
1569   // draw the crosshair
1570   if (m_bFreeMove)
1571   {
1572     // setup orthographic projection mode
1573     qglMatrixMode(GL_PROJECTION);
1574     //qglPushMatrix();
1575     qglLoadIdentity();
1576     qglDisable(GL_DEPTH_TEST);
1577     qglOrtho(0, (float)m_Camera.width, 0, (float)m_Camera.height, -100, 100);
1578     qglScalef(1, -1, 1);
1579           qglTranslatef(0, -(float)m_Camera.height, 0);
1580           qglMatrixMode(GL_MODELVIEW);
1581
1582     // draw crosshair
1583     //qglPushMatrix();
1584           qglLoadIdentity();
1585     qglColor3f( 1.f, 1.f, 1.f );
1586     qglBegin( GL_LINES );
1587     qglVertex2f( (float)m_Camera.width / 2.f, (float)m_Camera.height / 2.f + 6 );
1588     qglVertex2f( (float)m_Camera.width / 2.f, (float)m_Camera.height / 2.f + 2 );
1589     qglVertex2f( (float)m_Camera.width / 2.f, (float)m_Camera.height / 2.f - 6 );
1590     qglVertex2f( (float)m_Camera.width / 2.f, (float)m_Camera.height / 2.f - 2 );
1591     qglVertex2f( (float)m_Camera.width / 2.f + 6, (float)m_Camera.height / 2.f );
1592     qglVertex2f( (float)m_Camera.width / 2.f + 2, (float)m_Camera.height / 2.f );
1593     qglVertex2f( (float)m_Camera.width / 2.f - 6, (float)m_Camera.height / 2.f );
1594     qglVertex2f( (float)m_Camera.width / 2.f - 2, (float)m_Camera.height / 2.f );
1595     qglEnd();
1596     //qglPopMatrix();
1597
1598     // reset perspective projection
1599           //qglMatrixMode(GL_PROJECTION);
1600           //qglPopMatrix();
1601           //qglMatrixMode(GL_MODELVIEW);
1602   }
1603
1604 #if 0
1605         if ((g_qeglobals.d_select_mode == sel_area) && (g_nPatchClickedView == W_CAMERA))
1606         {
1607                 // setup orthographic projection mode
1608                 qglMatrixMode(GL_PROJECTION);
1609                 //qglPushMatrix();
1610                 qglLoadIdentity();
1611                 qglDisable(GL_DEPTH_TEST);
1612                 qglOrtho(0, (float)m_Camera.width, 0, (float)m_Camera.height, -100, 100);
1613                 //qglScalef(1, -1, 1);
1614                 //qglTranslatef(0, -(float)m_Camera.height, 0);
1615                 qglMatrixMode(GL_MODELVIEW);
1616
1617         // area selection hack
1618                 qglLoadIdentity();
1619                 qglDisable(GL_CULL_FACE);
1620                 qglEnable (GL_BLEND);
1621                 qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
1622                 qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1623                 qglColor4f(0.0, 0.0, 1.0, 0.25);
1624                 qglRectf(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[0], g_qeglobals.d_vAreaBR[1]);
1625                 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
1626                 qglDisable (GL_BLEND);
1627                 qglEnable (GL_CULL_FACE);
1628         }
1629 #endif
1630
1631   // bind back to the default texture so that we don't have problems
1632   // elsewhere using/modifying texture maps between contexts
1633   qglBindTexture( GL_TEXTURE_2D, 0 );
1634
1635   qglFinish();
1636   QE_CheckOpenGLForErrors();
1637   //    Sys_EndWait();
1638   if (m_Camera.timing)
1639   {
1640     end = Sys_DoubleTime ();
1641     Sys_Printf ("Camera: %i ms\n", (int)(1000*(end-start)));
1642   }
1643
1644   for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
1645     brush->bCamCulled = false;
1646
1647   for (brush = pList->next ; brush != pList ; brush=brush->next)
1648     brush->bCamCulled = false;
1649 }
1650
1651 void CamWnd::OnExpose ()
1652 {
1653   if (!MakeCurrent ())
1654   {
1655     Sys_Printf("ERROR: glXMakeCurrent failed..\n ");
1656     Sys_Printf("Please restart Radiant if the camera view is not working\n");
1657   }
1658   else
1659   {
1660     QE_CheckOpenGLForErrors();
1661     g_pSplitList = NULL;
1662     if (g_bClipMode)
1663     {
1664       if (g_Clip1.Set() && g_Clip2.Set())
1665       {
1666         g_pSplitList = (g_bSwitch) ?
1667           &g_brBackSplits : &g_brFrontSplits;
1668       }
1669     }
1670
1671     Patch_LODMatchAll(); // spog
1672
1673     Cam_Draw ();
1674     QE_CheckOpenGLForErrors ();
1675
1676     m_XORRectangle.set(rectangle_t());
1677     SwapBuffers ();
1678   }
1679 }
1680
1681 void CamWnd::BenchMark()
1682 {
1683   if (!MakeCurrent ())
1684     Error ("glXMakeCurrent failed in Benchmark");
1685
1686   qglDrawBuffer (GL_FRONT);
1687   double dStart = Sys_DoubleTime ();
1688   for (int i=0 ; i < 100 ; i++)
1689   {
1690     m_Camera.angles[YAW] = i*4;
1691     Cam_Draw();
1692   }
1693   SwapBuffers ();
1694   qglDrawBuffer (GL_BACK);
1695   double dEnd = Sys_DoubleTime ();
1696   Sys_Printf ("%5.2f seconds\n", dEnd - dStart);
1697 }