/* Copyright (C) 1999-2007 id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // // Camera Window // // Leonardo Zide (leo@lokigames.com) // #include "stdafx.h" #include #include extern void DrawPathLines(); extern void Select_ShiftTexture(int x, int y); extern void Select_RotateTexture(int amt); extern void DrawAlternatePoint(vec3_t v, float scale); //extern void Select_ScaleTexture(int x, int y); extern int g_nPatchClickedView; brush_t* g_pSplitList = NULL; // ============================================================================= // CamWnd class CamWnd::CamWnd () : GLWindow (TRUE), m_XORRectangle(m_pWidget) { m_nNumTransBrushes = 0; memset(&m_Camera, 0, sizeof(camera_t)); m_pSide_select = NULL; m_bClipMode = false; m_bFreeMove = false; Cam_Init(); } CamWnd::~CamWnd () { } void CamWnd::OnCreate () { if (!MakeCurrent ()) Error ("glMakeCurrent failed"); gtk_glwidget_create_font (m_pWidget); // report OpenGL information Sys_Printf ("GL_VENDOR: %s\n", qglGetString (GL_VENDOR)); Sys_Printf ("GL_RENDERER: %s\n", qglGetString (GL_RENDERER)); Sys_Printf ("GL_VERSION: %s\n", qglGetString (GL_VERSION)); Sys_Printf ("GL_EXTENSIONS: %s\n", qglGetString (GL_EXTENSIONS)); // Set off texture compression supported g_qeglobals.bTextureCompressionSupported = 0; // finalize OpenGL init // NOTE // why is this here? well .. the Gtk objects get constructed when you enter gtk_main // and I wanted to have the extensions information in the editor startup console (avoid looking that up in the early console) // RIANT // I Split this up so as to add support for extension and user-friendly // compression format selection. // ADD new globals for your new format so as to minimise // calls to Sys_QGL_ExtensionSupported // NOTE TTimo: I don't really like this approach with globals. Frequent calls to Sys_QGL_ExtensionSupported don't sound like // a problem to me. If there is some caching to be done, then I think it should be inside Sys_QGL_ExtensionSupported /////////////////////////////////////////// // Check for default OpenGL if (Sys_QGL_ExtensionSupported ("GL_ARB_texture_compression")) { g_qeglobals.bTextureCompressionSupported = 1; g_qeglobals.m_bOpenGLCompressionSupported = 1; } // INSERT PROPRIETARY EXTENSIONS HERE // Check for S3 extensions // create a bool global for extension supported if (Sys_QGL_ExtensionSupported ("GL_EXT_texture_compression_s3tc")) { g_qeglobals.bTextureCompressionSupported = 1; g_qeglobals.m_bS3CompressionSupported = 1; } g_qeglobals.m_bOpenGLReady = true; g_PrefsDlg.UpdateTextureCompression(); #ifdef ATIHACK_812 g_PrefsDlg.UpdateATIHack(); #endif g_qeglobals_gui.d_camera = m_pWidget; } void CamWnd::Cam_Init () { m_Camera.timing = false; m_Camera.origin[0] = 0.f; m_Camera.origin[1] = 20.f; m_Camera.origin[2] = 46.f; m_Camera.color[0] = 0.3f; m_Camera.color[1] = 0.3f; m_Camera.color[2] = 0.3f; m_nCambuttonstate = 0; } void CamWnd::OnSize(int cx, int cy) { m_Camera.width = cx; m_Camera.height = cy; gtk_widget_queue_draw(m_pWidget); } rectangle_t rectangle_from_area_cam() { const float left = MIN(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0]); const float top = MAX(g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1]); const float right = MAX(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0]); const float bottom = MIN(g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1]); return rectangle_t(left, bottom, right - left, top - bottom); } void update_xor_rectangle(XORRectangle& xor_rectangle) { rectangle_t rectangle; if ((g_qeglobals.d_select_mode == sel_area)) rectangle = rectangle_from_area_cam(); xor_rectangle.set(rectangle); } void CamWnd::OnMouseMove(guint32 flags, int pointx, int pointy) { int height = m_pWidget->allocation.height; // NOTE RR2DO2 this hasn't got any use anymore really. It is an old qeradiant feature // that can be re-enabled by removing the checks for HasCapture and not shift/ctrl down // but the scaling/rotating (unless done with the steps set in the surface inspector // dialog) is way too sensitive to be of any use if (HasCapture () && Sys_AltDown () && !((flags & MK_SHIFT) || (flags & MK_CONTROL))) { if (flags & MK_CONTROL) Select_RotateTexture(pointy - m_ptLastCursorY); else if (flags & MK_SHIFT) Select_ScaleTexture(pointx - m_ptLastCursorX, m_ptLastCursorY - pointy); else Select_ShiftTexture(pointx - m_ptLastCursorX, m_ptLastCursorY - pointy); } else { Cam_MouseMoved(pointx, height - 1 - pointy, flags); } m_ptLastCursorX = pointx; m_ptLastCursorY = pointy; update_xor_rectangle(m_XORRectangle); } void CamWnd::OnMouseWheel(bool bUp) { if (bUp) VectorMA (m_Camera.origin, g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); else VectorMA (m_Camera.origin, -g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); Sys_UpdateWindows (nUpdate); g_pParentWnd->OnTimer (); } void CamWnd::OnLButtonDown(guint32 nFlags, int pointx, int pointy) { m_ptLastCursorX = pointx; m_ptLastCursorY = pointy; OriginalMouseDown(nFlags, pointx, pointy); } void CamWnd::OnLButtonUp(guint32 nFlags, int pointx, int pointy) { OriginalMouseUp(nFlags, pointx, pointy); } void CamWnd::OnMButtonDown(guint32 nFlags, int pointx, int pointy) { OriginalMouseDown(nFlags, pointx, pointy); } void CamWnd::OnMButtonUp(guint32 nFlags, int pointx, int pointy) { OriginalMouseUp(nFlags, pointx, pointy); } void CamWnd::OnRButtonDown(guint32 nFlags, int pointx, int pointy) { OriginalMouseDown(nFlags, pointx, pointy); } void CamWnd::OnRButtonUp(guint32 nFlags, int pointx, int pointy) { OriginalMouseUp(nFlags, pointx, pointy); } void CamWnd::OriginalMouseUp(guint32 nFlags, int pointx, int pointy) { int height = m_pWidget->allocation.height; if(g_qeglobals.d_select_mode == sel_facets_on || g_qeglobals.d_select_mode == sel_facets_off) { g_qeglobals.d_select_mode = sel_brush; } Cam_MouseUp(pointx, height - 1 - pointy, nFlags); ReleaseCapture (); update_xor_rectangle(m_XORRectangle); } void CamWnd::OriginalMouseDown(guint32 nFlags, int pointx, int pointy) { int height = m_pWidget->allocation.height; SetFocus(); SetCapture(); Cam_MouseDown (pointx, height - 1 - pointy, nFlags); update_xor_rectangle(m_XORRectangle); } void CamWnd::Cam_BuildMatrix() { float ya; float matrix[4][4]; int i; if (!m_bFreeMove) { ya = m_Camera.angles[1]/180*Q_PI; // the movement matrix is kept 2d m_Camera.forward[0] = cos(ya); m_Camera.forward[1] = sin(ya); m_Camera.forward[2] = 0; m_Camera.right[0] = m_Camera.forward[1]; m_Camera.right[1] = -m_Camera.forward[0]; } else { AngleVectors( m_Camera.angles, m_Camera.forward, m_Camera.right, NULL ); m_Camera.forward[2] = -m_Camera.forward[2]; } memcpy(matrix, m_Camera.projection, sizeof(m4x4_t)); m4x4_multiply_by_m4x4(&matrix[0][0], &m_Camera.modelview[0][0]); //qglGetFloatv (GL_PROJECTION_MATRIX, &matrix[0][0]); for (i=0 ; i<3 ; i++) { m_Camera.vright[i] = matrix[i][0]; m_Camera.vup[i] = matrix[i][1]; m_Camera.vpn[i] = matrix[i][2]; } VectorNormalize (m_Camera.vright, m_Camera.vright); VectorNormalize (m_Camera.vup, m_Camera.vup); VectorNormalize (m_Camera.vpn, m_Camera.vpn); } void CamWnd::Cam_ChangeFloor (qboolean up) { brush_t *b; float d, bestd, current; vec3_t start, dir; start[0] = m_Camera.origin[0]; start[1] = m_Camera.origin[1]; start[2] = g_MaxWorldCoord; dir[0] = dir[1] = 0; dir[2] = -1; current = g_MaxWorldCoord - (m_Camera.origin[2] - 48); if (up) bestd = 0; else bestd = 2*g_MaxWorldCoord; for (b=active_brushes.next ; b != &active_brushes ; b=b->next) { if (!Brush_Ray (start, dir, b, &d)) continue; if (up && d < current && d > bestd) bestd = d; if (!up && d > current && d < bestd) bestd = d; } if (bestd == 0 || bestd == 2*g_MaxWorldCoord) return; m_Camera.origin[2] += current - bestd; Sys_UpdateWindows (W_CAMERA|W_Z_OVERLAY); } void CamWnd::Cam_PositionDrag() { int x, y; Sys_GetCursorPos (&x, &y); if (x != m_ptCursorX || y != m_ptCursorY) { x -= m_ptCursorX; VectorMA (m_Camera.origin, x, m_Camera.vright, m_Camera.origin); y -= m_ptCursorY; m_Camera.origin[2] -= y; Sys_SetCursorPos(m_ptCursorX, m_ptCursorY); Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY); } } void CamWnd::Cam_MouseControl (float dtime) { Cam_KeyControl (dtime); if( g_PrefsDlg.m_bCamFreeLook ) { int dx, dy; gint x, y; if( !m_bFreeMove || m_nCambuttonstate == MK_CONTROL ) return; // Update angles Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); dx = m_ptLastCamCursorX - m_ptCursorX; dy = m_ptLastCamCursorY - m_ptCursorY; gdk_window_get_origin( m_pWidget->window, &x, &y); m_ptLastCamCursorX = x + (m_Camera.width / 2); m_ptLastCamCursorY = y + (m_Camera.height / 2); Sys_SetCursorPos(m_ptLastCamCursorX, m_ptLastCamCursorY); // Don't use pitch if(!g_PrefsDlg.m_bCamFreeLookStrafe) { if (g_PrefsDlg.m_bCamInverseMouse) m_Camera.angles[PITCH] -= dy * dtime * g_PrefsDlg.m_nAngleSpeed; else m_Camera.angles[PITCH] += dy * dtime * g_PrefsDlg.m_nAngleSpeed; } else { VectorMA (m_Camera.origin, dy * (float) (g_PrefsDlg.m_nMoveSpeed / 6.0f), m_Camera.forward, m_Camera.origin); } m_Camera.angles[YAW] += dx * dtime * g_PrefsDlg.m_nAngleSpeed; if (m_Camera.angles[PITCH] > 90) m_Camera.angles[PITCH] = 90; else if (m_Camera.angles[PITCH] < -90) m_Camera.angles[PITCH] = -90; if (m_Camera.angles[YAW] >= 360) m_Camera.angles[YAW] = 0; else if (m_Camera.angles[YAW] <= -360) m_Camera.angles[YAW] = 0; if( dx || dy || m_Camera.movementflags ) { int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); Sys_UpdateWindows (nUpdate); g_pParentWnd->OnTimer (); } } else { int xl, xh; int yl, yh; float xf, yf; if (g_PrefsDlg.m_nMouseButtons == 2) { if (m_nCambuttonstate != (MK_RBUTTON | MK_SHIFT)) return; } else { if (m_nCambuttonstate != MK_RBUTTON) return; } xf = (float)(m_ptButtonX - m_Camera.width/2) / (m_Camera.width/2); yf = (float)(m_ptButtonY - m_Camera.height/2) / (m_Camera.height/2); xl = m_Camera.width/3; xh = xl*2; yl = m_Camera.height/3; yh = yl*2; xf *= 1.0 - fabs(yf); if (xf < 0) { xf += 0.1f; if (xf > 0) xf = 0; } else { xf -= 0.1f; if (xf < 0) xf = 0; } VectorMA (m_Camera.origin, yf*dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); m_Camera.angles[YAW] += xf*-dtime*g_PrefsDlg.m_nAngleSpeed; int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); Sys_UpdateWindows (nUpdate); g_pParentWnd->OnTimer (); } } void CamWnd::Cam_KeyControl (float dtime) { // Update angles if (m_Camera.movementflags & MOVE_ROTLEFT) m_Camera.angles[YAW] += 15*dtime*g_PrefsDlg.m_nAngleSpeed; if (m_Camera.movementflags & MOVE_ROTRIGHT) m_Camera.angles[YAW] -= 15*dtime*g_PrefsDlg.m_nAngleSpeed; // Update position if (m_Camera.movementflags & MOVE_FORWARD) VectorMA (m_Camera.origin, dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); if (m_Camera.movementflags & MOVE_BACK) VectorMA (m_Camera.origin, -dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); if (m_Camera.movementflags & MOVE_STRAFELEFT) VectorMA (m_Camera.origin, -dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.right, m_Camera.origin); if (m_Camera.movementflags & MOVE_STRAFERIGHT) VectorMA (m_Camera.origin, dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.right, m_Camera.origin); // Save a screen update (when m_bFreeMove is enabled, mousecontrol does the update) if( !m_bFreeMove && m_Camera.movementflags ) { int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); Sys_UpdateWindows (nUpdate); g_pParentWnd->OnTimer (); } } // NOTE TTimo if there's an OS-level focus out of the application // then we can release the camera cursor grab static gint camwindow_focusout(GtkWidget* widget, GdkEventKey* event, gpointer data) { g_pParentWnd->GetCamWnd ()->ToggleFreeMove(); return FALSE; } void CamWnd::ToggleFreeMove() { GdkWindow *window; GtkWidget *widget; m_bFreeMove = !m_bFreeMove; Camera()->movementflags = 0; m_ptLastCamCursorX = m_ptCursorX; m_ptLastCamCursorY = m_ptCursorY; if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) { widget = g_pParentWnd->GetCamWnd ()->m_pParent; window = widget->window; } else { widget = g_pParentWnd->m_pWidget; window = widget->window; } if (m_bFreeMove) { SetFocus(); SetCapture(); { GdkPixmap *pixmap; GdkBitmap *mask; char buffer [(32 * 32)/8]; memset (buffer, 0, (32 * 32)/8); GdkColor white = {0, 0xffff, 0xffff, 0xffff}; GdkColor black = {0, 0x0000, 0x0000, 0x0000}; pixmap = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); mask = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); GdkCursor *cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &white, &black, 1, 1); gdk_window_set_cursor (window, cursor); gdk_cursor_unref (cursor); gdk_drawable_unref (pixmap); gdk_drawable_unref (mask); } // RR2DO2: FIXME why does this only work the 2nd and // further times the event is called? (floating windows // mode seems to work fine though...) m_FocusOutHandler_id = gtk_signal_connect (GTK_OBJECT (widget), "focus_out_event", GTK_SIGNAL_FUNC (camwindow_focusout), g_pParentWnd); { GdkEventMask mask = (GdkEventMask)(GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gdk_pointer_grab(widget->window, TRUE, mask, widget->window, NULL, GDK_CURRENT_TIME); } } else { gdk_pointer_ungrab(GDK_CURRENT_TIME); gtk_signal_disconnect (GTK_OBJECT (widget), m_FocusOutHandler_id); GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR); gdk_window_set_cursor (window, cursor); gdk_cursor_unref (cursor); ReleaseCapture(); } int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); Sys_UpdateWindows (nUpdate); g_pParentWnd->OnTimer (); } void CamWnd::Cam_MouseDown(int x, int y, int buttons) { vec3_t dir; float f, r, u; int i; // // calc ray direction // u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); f = 1; for (i=0 ; i<3 ; i++) dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; VectorNormalize (dir, dir); Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); m_nCambuttonstate = buttons; m_ptButtonX = x; m_ptButtonY = y; // LBUTTON = manipulate selection // shift-LBUTTON = select // middle button = grab texture // ctrl-middle button = set entire brush to texture // ctrl-shift-middle button = set single face to texture int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; if ((buttons == MK_LBUTTON) || (buttons == (MK_LBUTTON | MK_SHIFT)) || (buttons == (MK_LBUTTON | MK_CONTROL)) || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) || (buttons == nMouseButton) || (buttons == (nMouseButton|MK_SHIFT)) || (buttons == (nMouseButton|MK_CONTROL)) || (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL))) { if (g_PrefsDlg.m_nMouseButtons == 2 && (buttons == (MK_RBUTTON | MK_SHIFT))) { if (g_PrefsDlg.m_bCamFreeLook) ToggleFreeMove(); else Cam_MouseControl (0.1f); } else { // something global needs to track which window is responsible for stuff Patch_SetView(W_CAMERA); Drag_Begin (x, y, buttons, m_Camera.vright, m_Camera.vup, m_Camera.origin, dir, true); } return; } if (buttons == MK_RBUTTON) { if (g_PrefsDlg.m_bCamFreeLook) ToggleFreeMove(); else Cam_MouseControl (0.1f); return; } } void CamWnd::Cam_MouseUp (int x, int y, int buttons) { m_nCambuttonstate = 0; Drag_MouseUp (buttons); } void CamWnd::Cam_MouseMoved (int x, int y, int buttons) { m_nCambuttonstate = buttons; if (!buttons) return; if( g_PrefsDlg.m_nCamDragMultiSelect ) { if (g_qeglobals.d_select_mode == sel_brush_on || g_qeglobals.d_select_mode == sel_brush_off) { bool bDoDragMultiSelect = FALSE; if( g_PrefsDlg.m_nCamDragMultiSelect == 1 && buttons == (MK_LBUTTON|MK_SHIFT) ) bDoDragMultiSelect = TRUE; else if( g_PrefsDlg.m_nCamDragMultiSelect == 2 && buttons == (MK_LBUTTON|MK_CONTROL) && Sys_AltDown() ) bDoDragMultiSelect = TRUE; if( bDoDragMultiSelect ) { vec3_t dir; float f, r, u; int i; // // calc ray direction // u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); f = 1; for (i=0 ; i<3 ; i++) dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; VectorNormalize (dir,dir); switch( g_qeglobals.d_select_mode ) { case sel_brush_on: Select_Ray( m_Camera.origin, dir, (SF_DRAG_ON|SF_CAMERA) ); break; case sel_brush_off: Select_Ray( m_Camera.origin, dir, (SF_DRAG_OFF|SF_CAMERA) ); break; default: break; } return; } } else if (g_qeglobals.d_select_mode == sel_facets_on || g_qeglobals.d_select_mode == sel_facets_off) { if( buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) ) { vec3_t dir; float f, r, u; int i; // // calc ray direction // u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); f = 1; for (i=0 ; i<3 ; i++) dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; VectorNormalize (dir,dir); switch( g_qeglobals.d_select_mode ) { case sel_facets_on: Select_Ray( m_Camera.origin, dir, (SF_SINGLEFACE|SF_DRAG_ON|SF_CAMERA) ); break; case sel_facets_off: Select_Ray( m_Camera.origin, dir, (SF_SINGLEFACE|SF_DRAG_OFF|SF_CAMERA) ); break; default: break; } return; } } } m_ptButtonX = x; m_ptButtonY = y; if ( (m_bFreeMove && (buttons & MK_CONTROL) && !(buttons & MK_SHIFT)) || (!m_bFreeMove && (buttons == (MK_RBUTTON|MK_CONTROL))) ) { Cam_PositionDrag (); Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); return; } Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); if (buttons & (MK_LBUTTON | MK_MBUTTON) ) { Drag_MouseMoved (x, y, buttons); if(g_qeglobals.d_select_mode != sel_area) Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); } } void CamWnd::InitCull() { int i; VectorSubtract (m_Camera.vpn, m_Camera.vright, m_vCull1); VectorAdd (m_Camera.vpn, m_Camera.vright, m_vCull2); for (i=0 ; i<3 ; i++) { if (m_vCull1[i] > 0) m_nCullv1[i] = 3+i; else m_nCullv1[i] = i; if (m_vCull2[i] > 0) m_nCullv2[i] = 3+i; else m_nCullv2[i] = i; } } qboolean CamWnd::CullBrush (brush_t *b) { int i; vec3_t point; float d; if (g_PrefsDlg.m_bCubicClipping) { float fLevel = g_PrefsDlg.m_nCubicScale * 64; point[0] = m_Camera.origin[0] - fLevel; point[1] = m_Camera.origin[1] - fLevel; point[2] = m_Camera.origin[2] - fLevel; for (i=0; i<3; i++) if (b->mins[i] < point[i] && b->maxs[i] < point[i]) return true; point[0] = m_Camera.origin[0] + fLevel; point[1] = m_Camera.origin[1] + fLevel; point[2] = m_Camera.origin[2] + fLevel; for (i=0; i<3; i++) if (b->mins[i] > point[i] && b->maxs[i] > point[i]) return true; } for (i=0 ; i<3 ; i++) point[i] = b->mins[m_nCullv1[i]] - m_Camera.origin[i]; d = DotProduct (point, m_vCull1); if (d < -1) return true; for (i=0 ; i<3 ; i++) point[i] = b->mins[m_nCullv2[i]] - m_Camera.origin[i]; d = DotProduct (point, m_vCull2); if (d < -1) return true; return false; } // project a 3D point onto the camera space // we use the GL viewing matrixes // this is the implementation of a glu function (I realized that afterwards): gluProject void CamWnd::ProjectCamera(const vec3_t A, vec_t B[2]) { vec_t P1[4],P2[4],P3[4]; VectorCopy(A,P1); P1[3] = 1; GLMatMul(m_Camera.modelview , P1, P2); GLMatMul(m_Camera.projection, P2, P3); // we ASSUME that the view port is 0 0 m_Camera.width m_Camera.height (you can check in Cam_Draw) B[0] = (float)m_Camera.width * ( P3[0] + 1.0 ) / 2.0; B[1] = (float)m_Camera.height * ( P3[1] + 1.0 ) / 2.0; } // vec defines a direction in geometric space and P an origin point // the user is interacting from the camera view // (for example with texture adjustment shortcuts) // and intuitively if he hits left / right / up / down // what happens in geometric space should match the left/right/up/down move in camera space // axis = 0: vec is along left/right // axis = 1: vec is along up/down // sgn = +1: same directions // sgn = -1: opposite directions // Implementation: // typical use case is giving a face center and a normalized vector // 1) compute start and endpoint, project them in camera view, get the direction // depending on the situation, we might bump into precision issues with that // 2) possible to compute the projected direction independently? // this solution would be better but right now I don't see how to do it.. void CamWnd::MatchViewAxes(const vec3_t P, const vec3_t vec, int &axis, float &sgn) { vec_t A[2],B[2],V[2]; ProjectCamera(P,A); vec3_t Q; VectorAdd(P,vec,Q); ProjectCamera(Q,B); // V is the vector projected in camera space V[0] = B[0] - A[0]; V[1] = B[1] - A[1]; if (fabs(V[0])>fabs(V[1])) { // best match is against right axis = 0; if (V[0]>0) sgn = +1; else sgn = -1; } else { // best match is against up axis = 1; if (V[1]>0) sgn = +1; else sgn = -1; } } #if 0 void CamWnd::DrawLightRadius(brush_t* pBrush) { // if lighting int nRadius = Brush_LightRadius(pBrush); if (nRadius > 0) { Brush_SetLightColor(pBrush); qglEnable (GL_BLEND); qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglDisable (GL_TEXTURE_2D); qglEnable(GL_TEXTURE_2D); qglDisable(GL_BLEND); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); } } #endif extern void DrawPatchMesh(patchMesh_t *pm); extern void DrawPatchControls(patchMesh_t *pm); extern void Brush_DrawFacingAngle (brush_t *b, entity_t *e); extern void Brush_DrawModel(brush_t *b, bool bTextured = false); extern void DrawModelOrigin(brush_t *b); extern void DrawModelBBox(brush_t *b); void CamWnd::Cam_DrawBrush(brush_t *b, int mode) { int nGLState = m_Camera.draw_glstate; int nModelMode = g_PrefsDlg.m_nEntityShowState; GLfloat material[4], identity[4]; VectorSet(identity, 0.8f, 0.8f, 0.8f); IShader *pShader; // lights if (b->owner->eclass->fixedsize && b->owner->eclass->nShowFlags & ECLASS_LIGHT && g_PrefsDlg.m_bNewLightDraw) { switch (mode) { case DRAW_SOLID: VectorCopy(b->owner->color, material); VectorScale(material, 0.8f, material); material[3] = 1.0f; qglColor4fv(material); if (g_PrefsDlg.m_bNewLightDraw) DrawLight(b->owner, nGLState, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, 0); break; } } // models else if(b->owner->eclass->fixedsize && b->owner->model.pRender && !(!IsBrushSelected(b) && (nModelMode & ENTITY_SELECTED_ONLY))) { switch (mode) { case DRAW_TEXTURED: if (!(nModelMode & ENTITY_WIREFRAME) && nModelMode != ENTITY_BOX) { VectorCopy(b->owner->eclass->color, material); material[3] = identity[3] = 1.0f; qglEnable(GL_CULL_FACE); if(!(nGLState & DRAW_GL_TEXTURE_2D)) qglColor4fv(material); else qglColor4fv(identity); if(nGLState & DRAW_GL_LIGHTING) qglShadeModel(GL_SMOOTH); b->owner->model.pRender->Draw(nGLState, DRAW_RF_CAM); } break; case DRAW_WIRE: VectorCopy(b->owner->eclass->color, material); material[3] = 1.0f; qglColor4fv(material); // model view mode "wireframe" or "selected wire" if(nModelMode & ENTITY_WIREFRAME) b->owner->model.pRender->Draw(nGLState, DRAW_RF_CAM); // model view mode "skinned and boxed" if(!(b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) ) { qglColor4fv(material); aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); } else if(nModelMode & ENTITY_BOXED) { aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); } /* if(!(nModelMode & ENTITY_BOXED) && b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) DrawModelOrigin(b); */ } } // patches else if (b->patchBrush) { bool bTrans = (b->pPatch->pShader->getTrans() < 1.0f); switch(mode) { case DRAW_TEXTURED: if (!g_bPatchWireFrame && ((nGLState & DRAW_GL_BLEND && bTrans) || (!(nGLState & DRAW_GL_BLEND) && !bTrans))) { qglDisable(GL_CULL_FACE); pShader = b->pPatch->pShader; VectorCopy(pShader->getTexture()->color, material); material[3] = identity[3] = pShader->getTrans(); if(nGLState & DRAW_GL_TEXTURE_2D) { qglColor4fv(identity); qglBindTexture(GL_TEXTURE_2D, pShader->getTexture()->texture_number); } else qglColor4fv(material); if(nGLState & DRAW_GL_LIGHTING) qglShadeModel(GL_SMOOTH); DrawPatchMesh(b->pPatch); } break; case DRAW_WIRE: if (g_bPatchWireFrame) { VectorCopy(b->pPatch->pShader->getTexture()->color, material); material[3] = 1.0; qglColor4fv(material); DrawPatchMesh(b->pPatch); } if ( b->pPatch->bSelected && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area || g_bPatchBendMode)) DrawPatchControls(b->pPatch); } } // brushes else if(b->owner->eclass->fixedsize) { switch(mode) { case DRAW_SOLID: VectorCopy(b->owner->eclass->color, material); VectorScale(material, 0.8f, material); material[3] = 1.0f; qglColor4fv(material); qglEnable(GL_CULL_FACE); qglShadeModel(GL_FLAT); Brush_Draw(b); break; case DRAW_WIRE: if((g_qeglobals.d_savedinfo.include & INCLUDE_ANGLES) && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) Brush_DrawFacingAngle(b, b->owner); } } // brushes else { switch(mode) { case DRAW_TEXTURED: qglEnable(GL_CULL_FACE); qglShadeModel(GL_FLAT); Brush_Draw(b); } } } void CamWnd::Cam_DrawBrushes(int mode) { brush_t *b; brush_t *pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes; for(b = active_brushes.next; b != &active_brushes; b=b->next) if (!b->bFiltered && !b->bCamCulled) Cam_DrawBrush(b, mode); for(b = pList->next; b != pList; b=b->next) if (!b->bFiltered && !b->bCamCulled) Cam_DrawBrush(b, mode); } void CamWnd::Cam_DrawStuff() { GLfloat identity[4]; VectorSet(identity, 0.8f, 0.8f, 0.8f); brush_t *b; for(b = active_brushes.next; b != &active_brushes; b=b->next) b->bCamCulled = CullBrush(b); for(b = selected_brushes.next; b != &selected_brushes; b=b->next) b->bCamCulled = CullBrush(b); switch (m_Camera.draw_mode) { case cd_wire: qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); qglDisable(GL_TEXTURE_2D); qglDisable(GL_TEXTURE_1D); qglDisable(GL_BLEND); qglEnable(GL_DEPTH_TEST); qglEnableClientState(GL_VERTEX_ARRAY); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglShadeModel(GL_FLAT); if(g_PrefsDlg.m_bGLLighting) { qglDisable(GL_LIGHTING); qglDisable(GL_COLOR_MATERIAL); qglDisableClientState(GL_NORMAL_ARRAY); } m_Camera.draw_glstate = DRAW_GL_WIRE; break; case cd_solid: qglCullFace(GL_FRONT); qglEnable(GL_CULL_FACE); qglShadeModel (GL_FLAT); qglPolygonMode (GL_FRONT, GL_LINE); qglPolygonMode (GL_BACK, GL_FILL); qglDisable(GL_TEXTURE_2D); qglDisable(GL_BLEND); qglEnable(GL_DEPTH_TEST); qglEnableClientState(GL_VERTEX_ARRAY); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglPolygonOffset(-1.0, 2); if(g_PrefsDlg.m_bGLLighting) { qglEnable(GL_LIGHTING); qglEnable(GL_COLOR_MATERIAL); // qglEnable(GL_RESCALE_NORMAL); qglEnableClientState(GL_NORMAL_ARRAY); } m_Camera.draw_glstate = DRAW_GL_SOLID; break; case cd_texture: qglCullFace(GL_FRONT); qglEnable(GL_CULL_FACE); qglShadeModel (GL_FLAT); qglPolygonMode (GL_FRONT, GL_LINE); qglPolygonMode (GL_BACK, GL_FILL); qglEnable(GL_TEXTURE_2D); qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); qglDisable(GL_BLEND); qglEnable(GL_DEPTH_TEST); qglEnableClientState(GL_VERTEX_ARRAY); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); if(g_PrefsDlg.m_bGLLighting) { qglEnable(GL_LIGHTING); qglDisable(GL_COLOR_MATERIAL); qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identity); qglEnableClientState(GL_NORMAL_ARRAY); // qglEnable(GL_RESCALE_NORMAL); } qglPolygonOffset(-1.0, 2); m_Camera.draw_glstate = DRAW_GL_TEXTURED; break; default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); } Cam_DrawBrushes(DRAW_TEXTURED); // setup for solid stuff switch(m_Camera.draw_mode) { case cd_texture: qglDisable(GL_TEXTURE_2D); m_Camera.draw_glstate &= ~DRAW_GL_TEXTURE_2D; if(g_PrefsDlg.m_bGLLighting) qglEnable(GL_COLOR_MATERIAL); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); break; case cd_solid: break; case cd_wire: break; default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); } qglEnable(GL_CULL_FACE); qglShadeModel(GL_FLAT); Cam_DrawBrushes(DRAW_SOLID); // setup for wireframe stuff switch(m_Camera.draw_mode) { case cd_texture: if(g_PrefsDlg.m_bGLLighting) { qglDisable(GL_LIGHTING); qglDisable(GL_COLOR_MATERIAL); qglDisableClientState(GL_NORMAL_ARRAY); // qglDisable(GL_RESCALE_NORMAL); } qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break; case cd_solid: if(g_PrefsDlg.m_bGLLighting) { qglDisable(GL_LIGHTING); qglDisable(GL_COLOR_MATERIAL); qglDisableClientState(GL_NORMAL_ARRAY); // qglDisable(GL_RESCALE_NORMAL); } qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break; case cd_wire: break; default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); } qglDisable(GL_CULL_FACE); Cam_DrawBrushes(DRAW_WIRE); // setup for transparent texture stuff switch(m_Camera.draw_mode) { case cd_texture: qglPolygonMode (GL_FRONT, GL_LINE); qglPolygonMode (GL_BACK, GL_FILL); if(g_PrefsDlg.m_bGLLighting) { qglEnable(GL_COLOR_MATERIAL); qglEnableClientState(GL_NORMAL_ARRAY); qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identity); } qglEnable(GL_TEXTURE_2D); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); m_Camera.draw_glstate = DRAW_GL_TEXTURED; break; case cd_solid: qglPolygonMode (GL_FRONT, GL_LINE); qglPolygonMode (GL_BACK, GL_FILL); if(g_PrefsDlg.m_bGLLighting) { qglEnable(GL_LIGHTING); qglEnable(GL_COLOR_MATERIAL); qglEnableClientState(GL_NORMAL_ARRAY); // qglEnable(GL_RESCALE_NORMAL); } m_Camera.draw_glstate = DRAW_GL_SOLID; break; case cd_wire: m_Camera.draw_glstate = DRAW_GL_WIRE; break; default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); } qglEnable(GL_BLEND); m_Camera.draw_glstate |= DRAW_GL_BLEND; qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // FIXME: some .TGA are buggy, have a completely empty alpha channel // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE // so I decided using GL_DECAL instead // if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent. // this could get better if you can get qglTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome // Arnout: empty alpha channels are now always filled with data. Don't set this anymore (would cause problems with qer_alphafunc too) // qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); Cam_DrawBrushes(DRAW_TEXTURED); // qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); qglDisable(GL_BLEND); // setup for wireframe stuff switch(m_Camera.draw_mode) { case cd_texture: if(g_PrefsDlg.m_bGLLighting) { qglDisable(GL_COLOR_MATERIAL); qglDisable(GL_LIGHTING); // qglDisable(GL_RESCALE_NORMAL); } break; case cd_solid: if(g_PrefsDlg.m_bGLLighting) { qglDisable(GL_COLOR_MATERIAL); qglDisable(GL_LIGHTING); // qglDisable(GL_RESCALE_NORMAL); } break; case cd_wire: break; default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); } } /* ============== Cam_Draw ============== */ void QueueClear (); void QueueDraw (); void CamWnd::Cam_Draw() { brush_t *brush; face_t *face; float screenaspect; float yfov; double start = 0.0, end; int i; if (!active_brushes.next) return; // not valid yet if (m_Camera.timing) start = Sys_DoubleTime (); // // clear // QE_CheckOpenGLForErrors(); qglViewport(0, 0, m_Camera.width, m_Camera.height); 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); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // // set up viewpoint // qglMatrixMode(GL_PROJECTION); qglLoadIdentity (); screenaspect = (float)m_Camera.width / m_Camera.height; yfov = 2*atan((float)m_Camera.height / m_Camera.width)*180/Q_PI; qgluPerspective (yfov, screenaspect, 8, 32768); // we're too lazy to calc projection matrix ourselves!!! qglGetFloatv (GL_PROJECTION_MATRIX, &m_Camera.projection[0][0]); vec3_t vec; m4x4_identity(&m_Camera.modelview[0][0]); VectorSet(vec, -90, 0, 0); m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); VectorSet(vec, 0, 0, 90); m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); VectorSet(vec, 0, m_Camera.angles[0], 0); m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); VectorSet(vec, 0, 0, -m_Camera.angles[1]); m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); VectorSet(vec, -m_Camera.origin[0], -m_Camera.origin[1], -m_Camera.origin[2]); m4x4_translate_by_vec3(&m_Camera.modelview[0][0], vec); Cam_BuildMatrix (); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); qglMultMatrixf(&m_Camera.modelview[0][0]); // grab the GL_PROJECTION and GL_MODELVIEW matrixes // used in GetRelativeAxes //qglGetFloatv (GL_PROJECTION_MATRIX, &m_Camera.projection[0][0]); //qglGetFloatv (GL_MODELVIEW_MATRIX, &m_Camera.modelview[0][0]); #if 0 // TTimo: this is not used, just for verification (0, 0, m_Camera.width, m_Camera.height) GLint viewprt[4]; qglGetIntegerv (GL_VIEWPORT, viewprt); #endif if (g_PrefsDlg.m_bGLLighting) { GLfloat inverse_cam_dir[4], ambient[4], diffuse[4];//, material[4]; ambient[0] = ambient[1] = ambient[2] = 0.6f; ambient[3] = 1.0f; diffuse[0] = diffuse[1] = diffuse[2] = 0.4f; diffuse[3] = 1.0f; //material[0] = material[1] = material[2] = 0.8f; //material[3] = 1.0f; vec3_t vCam, vRotate; VectorSet(vCam, -1, 0, 0); //default cam pos VectorSet(vRotate, 0, -m_Camera.angles[0], 0); VectorRotate(vCam, vRotate, vCam); VectorSet(vRotate, 0, 0, m_Camera.angles[1]); VectorRotate(vCam, vRotate, vCam); inverse_cam_dir[0] = vCam[0]; inverse_cam_dir[1] = vCam[1]; inverse_cam_dir[2] = vCam[2]; inverse_cam_dir[3] = 0; qglColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); qglLightfv(GL_LIGHT0, GL_POSITION, inverse_cam_dir); qglLightfv(GL_LIGHT0, GL_AMBIENT, ambient); qglLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); qglEnable(GL_LIGHT0); } InitCull (); // // draw stuff // Cam_DrawStuff(); qglEnableClientState(GL_VERTEX_ARRAY); qglDisableClientState(GL_NORMAL_ARRAY); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisable (GL_TEXTURE_2D); qglDisable (GL_LIGHTING); qglDisable (GL_COLOR_MATERIAL); qglEnable (GL_CULL_FACE); brush_t* pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes; if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL) { 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); qglEnable (GL_BLEND); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglDepthFunc (GL_LEQUAL); for (brush = pList->next ; brush != pList ; brush=brush->next) { if (brush->bCamCulled) // draw selected faces of filtered brushes to remind that there is a selection continue; if (brush->patchBrush && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area)) continue; if (!g_PrefsDlg.m_bPatchBBoxSelect && brush->patchBrush) { DrawPatchMesh(brush->pPatch); } else if(brush->owner->model.pRender && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) { brush->owner->model.pRender->Draw(DRAW_GL_FLAT, (DRAW_RF_SEL_OUTLINE|DRAW_RF_CAM)); } else { for (face=brush->brush_faces ; face ; face=face->next) Brush_FaceDraw(face, DRAW_GL_FLAT); } } int nCount = g_ptrSelectedFaces.GetSize(); if (nCount > 0) { for (int i = 0; i < nCount; i++) { face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); Brush_FaceDraw(selFace, DRAW_GL_FLAT); } } qglDisableClientState(GL_NORMAL_ARRAY); qglDepthFunc (GL_LESS); } if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) { // non-zbuffered outline qglDisable (GL_BLEND); qglDisable (GL_DEPTH_TEST); qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); qglColor3f (1, 1, 1); for (brush = pList->next ; brush != pList ; brush=brush->next) { if ((brush->patchBrush && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area))) continue; if (!g_PrefsDlg.m_bPatchBBoxSelect && brush->patchBrush) { DrawPatchMesh(brush->pPatch); } else if(brush->owner->model.pRender && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) { brush->owner->model.pRender->Draw(DRAW_GL_WIRE, (DRAW_RF_SEL_FILL|DRAW_RF_CAM)); // Hydra : always draw bbox outline! aabb_draw(brush->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); } else { for (face=brush->brush_faces ; face ; face=face->next) Brush_FaceDraw(face, DRAW_GL_WIRE); } } } // edge / vertex flags if (g_qeglobals.d_select_mode == sel_vertex) { // GL_POINTS on Kyro Workaround if(!g_PrefsDlg.m_bGlPtWorkaround) { // brush verts qglPointSize (4); qglColor3f (0,1,0); qglBegin (GL_POINTS); for (i=0 ; inext) brush->bCamCulled = false; for (brush = pList->next ; brush != pList ; brush=brush->next) brush->bCamCulled = false; } void CamWnd::OnExpose () { if (!MakeCurrent ()) { Sys_Printf("ERROR: glXMakeCurrent failed..\n "); Sys_Printf("Please restart Radiant if the camera view is not working\n"); } else { QE_CheckOpenGLForErrors(); g_pSplitList = NULL; if (g_bClipMode) { if (g_Clip1.Set() && g_Clip2.Set()) { g_pSplitList = (g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits; } } Patch_LODMatchAll(); // spog Cam_Draw (); QE_CheckOpenGLForErrors (); m_XORRectangle.set(rectangle_t()); SwapBuffers (); } } void CamWnd::BenchMark() { if (!MakeCurrent ()) Error ("glXMakeCurrent failed in Benchmark"); qglDrawBuffer (GL_FRONT); double dStart = Sys_DoubleTime (); for (int i=0 ; i < 100 ; i++) { m_Camera.angles[YAW] = i*4; Cam_Draw(); } SwapBuffers (); qglDrawBuffer (GL_BACK); double dEnd = Sys_DoubleTime (); Sys_Printf ("%5.2f seconds\n", dEnd - dStart); }