Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

XYWnd.cpp

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // XYWnd.cpp : implementation file
00023 //
00024 // QERadiant
00025 //
00026 // 
00027 
00028 #include "stdafx.h"
00029 #include "Radiant.h"
00030 #include "XYWnd.h"
00031 #include "qe3.h"
00032 #include "PrefsDlg.h"
00033 #include "DialogInfo.h"
00034 #include "splines/splines.h"
00035 
00036 #ifdef _DEBUG
00037 #define new DEBUG_NEW
00038 #undef THIS_FILE
00039 static char THIS_FILE[] = __FILE__;
00040 #endif
00041 
00042 #define PAGEFLIPS   2
00043 
00044 
00045 const char* g_pDimStrings[] = {"x:%.f", "y:%.f", "z:%.f"};
00046 const char* g_pOrgStrings[] = {"(x:%.f  y:%.f)", "(x:%.f  z:%.f)", "(y:%.f  z:%.f)"};
00047 CString g_strDim;
00048 CString g_strStatus;
00049 
00050 bool g_bCrossHairs = false;
00051 bool g_bScaleMode;
00052 int g_nScaleHow;
00053 bool g_bRotateMode;
00054 bool g_bClipMode;
00055 bool g_bRogueClipMode;
00056 bool g_bSwitch;
00057 CClipPoint g_Clip1;
00058 CClipPoint g_Clip2;
00059 CClipPoint g_Clip3;
00060 CClipPoint* g_pMovingClip;
00061 brush_t g_brFrontSplits;
00062 brush_t g_brBackSplits;
00063 
00064 brush_t g_brClipboard;
00065 brush_t g_brUndo;
00066 entity_t    g_enClipboard;
00067 
00068 vec3_t g_vRotateOrigin;
00069 vec3_t g_vRotation;
00070 
00071 bool g_bPathMode;
00072 CClipPoint g_PathPoints[256];
00073 CClipPoint* g_pMovingPath;
00074 int g_nPathCount;
00075 int g_nPathLimit;
00076 
00077 bool g_bSmartGo;
00078 
00079 bool g_bPointMode;
00080 CClipPoint g_PointPoints[512];
00081 CClipPoint* g_pMovingPoint;
00082 int g_nPointCount;
00083 int g_nPointLimit;
00084 
00085 
00086 const int XY_LEFT = 0x01;
00087 const int XY_RIGHT = 0x02;
00088 const int XY_UP = 0x04;
00089 const int XY_DOWN = 0x08;
00090 
00091 PFNPathCallback* g_pPathFunc = NULL;
00092 
00093 void AcquirePath(int nCount, PFNPathCallback* pFunc)
00094 {
00095   g_nPathCount = 0;
00096   g_nPathLimit = nCount;
00097   g_pPathFunc = pFunc;
00098   g_bPathMode = true;
00099 }
00100 
00101 
00102 CPtrArray g_ptrMenus;
00103 
00104 CMemFile g_Clipboard(4096);
00105 CMemFile g_PatchClipboard(4096);
00106 
00107 extern int pressx;
00108 extern int pressy;
00109 
00110 
00112 // CXYWnd
00113 
00114 IMPLEMENT_DYNCREATE(CXYWnd, CWnd);
00115 
00116 CXYWnd::CXYWnd()
00117 {
00118   g_brClipboard.next = &g_brClipboard;
00119   g_brUndo.next = &g_brUndo;
00120   g_nScaleHow = 0;
00121   g_bRotateMode = false;
00122   g_bClipMode = false;
00123   g_bRogueClipMode = false;
00124   g_bSwitch = true;
00125   g_pMovingClip = NULL;
00126   g_pMovingPath = NULL;
00127   g_brFrontSplits.next = &g_brFrontSplits;
00128   g_brBackSplits.next = &g_brBackSplits;
00129   m_bActive = false;
00130   //m_bTiming = true;
00131   m_bTiming = false;
00132   m_bRButtonDown = false;
00133   m_nUpdateBits = W_XY;
00134   g_bPathMode = false;
00135   g_nPathCount = 0;
00136   g_nPathLimit = 0;
00137   m_nTimerID = -1;
00138   XY_Init();
00139 }
00140 
00141 CXYWnd::~CXYWnd()
00142 {
00143   int nSize = g_ptrMenus.GetSize();
00144   while (nSize > 0)
00145   {
00146     CMenu* pMenu = reinterpret_cast<CMenu*>(g_ptrMenus.GetAt(nSize-1));
00147     ASSERT(pMenu);
00148     pMenu->DestroyMenu();
00149     delete pMenu;
00150     nSize--;
00151   }
00152   g_ptrMenus.RemoveAll();
00153   m_mnuDrop.DestroyMenu();
00154 }
00155 
00156 
00157 BEGIN_MESSAGE_MAP(CXYWnd, CWnd)
00158     //{{AFX_MSG_MAP(CXYWnd)
00159     ON_WM_CREATE()
00160     ON_WM_LBUTTONDOWN()
00161     ON_WM_MBUTTONDOWN()
00162     ON_WM_RBUTTONDOWN()
00163     ON_WM_LBUTTONUP()
00164     ON_WM_MBUTTONUP()
00165     ON_WM_RBUTTONUP()
00166     ON_WM_MOUSEMOVE()
00167     ON_WM_PAINT()
00168     ON_WM_KEYDOWN()
00169     ON_WM_SIZE()
00170     ON_WM_DESTROY()
00171     ON_COMMAND(ID_SELECT_MOUSEROTATE, OnSelectMouserotate)
00172     ON_WM_TIMER()
00173     ON_WM_KEYUP()
00174     ON_WM_NCCALCSIZE()
00175     ON_WM_KILLFOCUS()
00176     ON_WM_SETFOCUS()
00177     ON_WM_CLOSE()
00178     ON_COMMAND(ID_SELECTION_MAKE_DETAIL, CMainFrame::OnSelectionMakeDetail)
00179     ON_COMMAND(ID_SELECTION_MAKE_STRUCTURAL, CMainFrame::OnSelectionMakeStructural)
00180     ON_COMMAND(ID_SELECTION_SELECTCOMPLETETALL, CMainFrame::OnSelectionSelectcompletetall)
00181     ON_COMMAND(ID_SELECTION_SELECTINSIDE, CMainFrame::OnSelectionSelectinside)
00182     ON_COMMAND(ID_SELECTION_SELECTPARTIALTALL, CMainFrame::OnSelectionSelectpartialtall)
00183     ON_COMMAND(ID_SELECTION_SELECTTOUCHING, CMainFrame::OnSelectionSelecttouching)
00184     ON_COMMAND(ID_SELECTION_UNGROUPENTITY, CMainFrame::OnSelectionUngroupentity)
00185     //}}AFX_MSG_MAP
00186   ON_COMMAND_RANGE(ID_ENTITY_START, ID_ENTITY_END, OnEntityCreate)
00187 END_MESSAGE_MAP()
00188 
00189 
00191 // CXYWnd message handlers
00192 LONG WINAPI XYWndProc(HWND, UINT, WPARAM, LPARAM);
00193 BOOL CXYWnd::PreCreateWindow(CREATESTRUCT& cs) 
00194 {
00195   WNDCLASS wc;
00196   HINSTANCE hInstance = AfxGetInstanceHandle();
00197   if (::GetClassInfo(hInstance, XY_WINDOW_CLASS, &wc) == FALSE)
00198   {
00199     // Register a new class
00200     memset (&wc, 0, sizeof(wc));
00201     wc.style         = CS_NOCLOSE | CS_OWNDC;
00202     wc.lpszClassName = XY_WINDOW_CLASS;
00203     wc.hCursor       = NULL; //LoadCursor (NULL,IDC_ARROW);
00204     wc.lpfnWndProc   = ::DefWindowProc;
00205     if (AfxRegisterClass(&wc) == FALSE)
00206       Error ("CCamWnd RegisterClass: failed");
00207   }
00208 
00209   cs.lpszClass = XY_WINDOW_CLASS;
00210   cs.lpszName = "VIEW";
00211   if (cs.style != QE3_CHILDSTYLE)
00212     cs.style = QE3_SPLITTER_STYLE;
00213 
00214     return CWnd::PreCreateWindow(cs);
00215 }
00216 
00217 HDC   s_hdcXY;
00218 HGLRC s_hglrcXY;
00219 
00220 static unsigned s_stipple[32] =
00221 {
00222     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
00223     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
00224     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
00225     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
00226     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
00227     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
00228     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
00229     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
00230 };
00231 
00232 /*
00233 ============
00234 WXY_WndProc
00235 ============
00236 */
00237 LONG WINAPI XYWndProc (
00238     HWND    hWnd,
00239     UINT    uMsg,
00240     WPARAM  wParam,
00241     LPARAM  lParam)
00242 {
00243     switch (uMsg)
00244     {
00245     case WM_DESTROY:
00246         QEW_StopGL( hWnd, s_hglrcXY, s_hdcXY );
00247         return 0;
00248 
00249     case WM_NCCALCSIZE:// don't let windows copy pixels
00250         DefWindowProc (hWnd, uMsg, wParam, lParam);
00251         return WVR_REDRAW;
00252 
00253     case WM_KILLFOCUS:
00254     case WM_SETFOCUS:
00255         SendMessage( hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0 );
00256         return 0;
00257 
00258     case WM_CLOSE:
00259         DestroyWindow (hWnd);
00260         return 0;
00261     }
00262 
00263     return DefWindowProc (hWnd, uMsg, wParam, lParam);
00264 }
00265 
00266 
00267 static void WXY_InitPixelFormat( PIXELFORMATDESCRIPTOR *pPFD )
00268 {
00269     memset( pPFD, 0, sizeof( *pPFD ) );
00270 
00271     pPFD->nSize    = sizeof( PIXELFORMATDESCRIPTOR );
00272     pPFD->nVersion = 1;
00273     pPFD->dwFlags  = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
00274     pPFD->iPixelType = PFD_TYPE_RGBA;
00275     pPFD->cColorBits = 24;
00276     pPFD->cDepthBits = 32;
00277     pPFD->iLayerType = PFD_MAIN_PLANE;
00278 
00279 }
00280 
00281 void WXY_Print( void )
00282 {
00283     DOCINFO di;
00284 
00285     PRINTDLG pd;
00286 
00287     /*
00288     ** initialize the PRINTDLG struct and execute it
00289     */
00290     memset( &pd, 0, sizeof( pd ) );
00291     pd.lStructSize = sizeof( pd );
00292     pd.hwndOwner = g_qeglobals.d_hwndXY;
00293     pd.Flags = PD_RETURNDC;
00294     pd.hInstance = 0;
00295     if ( !PrintDlg( &pd ) || !pd.hDC )
00296     {
00297         MessageBox( g_qeglobals.d_hwndMain, "Could not PrintDlg()", "QE4 Print Error", MB_OK | MB_ICONERROR );
00298         return;
00299     }
00300 
00301     /*
00302     ** StartDoc
00303     */
00304     memset( &di, 0, sizeof( di ) );
00305     di.cbSize = sizeof( di );
00306     di.lpszDocName = "QE4";
00307     if ( StartDoc( pd.hDC, &di ) <= 0 )
00308     {
00309         MessageBox( g_qeglobals.d_hwndMain, "Could not StartDoc()", "QE4 Print Error", MB_OK | MB_ICONERROR );
00310         return;
00311     }
00312 
00313     /*
00314     ** StartPage
00315     */
00316     if ( StartPage( pd.hDC ) <= 0 )
00317     {
00318         MessageBox( g_qeglobals.d_hwndMain, "Could not StartPage()", "QE4 Print Error", MB_OK | MB_ICONERROR );
00319         return;
00320     }
00321 
00322     /*
00323     ** read pixels from the XY window
00324     */
00325     {
00326         int bmwidth = 320, bmheight = 320;
00327         int pwidth, pheight;
00328 
00329         RECT r;
00330 
00331         GetWindowRect( g_qeglobals.d_hwndXY, &r );
00332 
00333         bmwidth  = r.right - r.left;
00334         bmheight = r.bottom - r.top;
00335 
00336         pwidth  = GetDeviceCaps( pd.hDC, PHYSICALWIDTH ) - GetDeviceCaps( pd.hDC, PHYSICALOFFSETX );
00337         pheight = GetDeviceCaps( pd.hDC, PHYSICALHEIGHT ) - GetDeviceCaps( pd.hDC, PHYSICALOFFSETY );
00338 
00339         StretchBlt( pd.hDC,
00340             0, 0,
00341             pwidth, pheight,
00342             s_hdcXY,
00343             0, 0,
00344             bmwidth, bmheight,
00345             SRCCOPY );
00346     }
00347 
00348     /*
00349     ** EndPage and EndDoc
00350     */
00351     if ( EndPage( pd.hDC ) <= 0 )
00352     {
00353         MessageBox( g_qeglobals.d_hwndMain, "QE4 Print Error", "Could not EndPage()", MB_OK | MB_ICONERROR );
00354         return;
00355     }
00356 
00357     if ( EndDoc( pd.hDC ) <= 0 )
00358     {
00359         MessageBox( g_qeglobals.d_hwndMain, "QE4 Print Error", "Could not EndDoc()", MB_OK | MB_ICONERROR );
00360         return;
00361     }
00362 }
00363 
00364 int CXYWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) 
00365 {
00366     if (CWnd::OnCreate(lpCreateStruct) == -1)
00367         return -1;
00368 
00369   s_hdcXY = ::GetDC(GetSafeHwnd());
00370     QEW_SetupPixelFormat(s_hdcXY, false);
00371     if ( ( s_hglrcXY = qwglCreateContext( s_hdcXY ) ) == 0 )
00372       Error( "wglCreateContext in WXY_WndProc failed" );
00373 
00374     if (!qwglShareLists( g_qeglobals.d_hglrcBase, s_hglrcXY ) )
00375       Error( "wglShareLists in WXY_WndProc failed" );
00376 
00377   if (!qwglMakeCurrent( s_hdcXY, s_hglrcXY ))
00378       Error ("wglMakeCurrent failed");
00379 
00380     qglPolygonStipple ((unsigned char *)s_stipple);
00381     qglLineStipple (3, 0xaaaa);
00382   g_qeglobals.d_hwndXY = GetSafeHwnd();
00383     return 0;
00384 }
00385 
00386 float ptSum(vec3_t pt)
00387 {
00388   return pt[0] + pt[1] + pt[2];
00389 }
00390 
00391 void CXYWnd::DropClipPoint(UINT nFlags, CPoint point)
00392 {
00393   CRect rctZ;
00394   GetClientRect(rctZ);
00395   if (g_pMovingClip)
00396   {
00397     SetCapture();
00398     SnapToPoint (point.x, rctZ.Height() - 1 - point.y , *g_pMovingClip);
00399   }
00400   else
00401   {
00402     vec3_t* pPt = NULL;
00403     if (g_Clip1.Set() == false)
00404     {
00405       pPt = g_Clip1;
00406       g_Clip1.Set(true);
00407       g_Clip1.m_ptScreen = point;
00408     }
00409     else 
00410     if (g_Clip2.Set() == false)
00411     {
00412       pPt = g_Clip2;
00413       g_Clip2.Set(true);
00414       g_Clip2.m_ptScreen = point;
00415     }
00416     else 
00417     if (g_Clip3.Set() == false)
00418     {
00419       pPt = g_Clip3;
00420       g_Clip3.Set(true);
00421       g_Clip3.m_ptScreen = point;
00422     }
00423     else 
00424     {
00425       RetainClipMode(true);
00426       pPt = g_Clip1;
00427       g_Clip1.Set(true);
00428       g_Clip1.m_ptScreen = point;
00429     }
00430     SnapToPoint (point.x, rctZ.Height() - 1 - point.y , *pPt);
00431   }
00432   Sys_UpdateWindows(XY | W_CAMERA_IFON);
00433 }
00434 
00435 
00436 void CXYWnd::DropPathPoint(UINT nFlags, CPoint point)
00437 {
00438   CRect rctZ;
00439   GetClientRect(rctZ);
00440   if (g_pMovingPath)
00441   {
00442     SetCapture();
00443     SnapToPoint (point.x, rctZ.Height() - 1 - point.y , *g_pMovingPath);
00444   }
00445   else
00446   {
00447     g_PathPoints[g_nPathCount].Set(true);
00448     g_PathPoints[g_nPathCount].m_ptScreen = point;
00449     SnapToPoint(point.x, rctZ.Height() - 1 - point.y, g_PathPoints[g_nPathCount]);
00450     g_nPathCount++;
00451     if (g_nPathCount == g_nPathLimit)
00452     {
00453       if (g_pPathFunc)
00454         g_pPathFunc(true, g_nPathCount);
00455       g_nPathCount = 0;
00456       g_bPathMode = false;
00457       g_pPathFunc = NULL;
00458     }
00459   }
00460   Sys_UpdateWindows(XY | W_CAMERA_IFON);
00461 }
00462 
00463 void CXYWnd::AddPointPoint(UINT nFlags, vec3_t* pVec)
00464 {
00465   g_PointPoints[g_nPointCount].Set(true);
00466   //g_PointPoints[g_nPointCount].m_ptScreen = point;
00467   _VectorCopy(*pVec, g_PointPoints[g_nPointCount]);
00468   g_PointPoints[g_nPointCount].SetPointPtr(pVec);
00469   g_nPointCount++;
00470   Sys_UpdateWindows(XY | W_CAMERA_IFON);
00471 }
00472 
00473 
00474 void CXYWnd::OnLButtonDown(UINT nFlags, CPoint point) 
00475 {
00476   g_pParentWnd->SetActiveXY(this);
00477   UndoCopy();
00478 
00479     // plugin entities
00480     if (DispatchOnLButtonDown(nFlags, point.x, point.y ))
00481         return;
00482 
00483   if (ClipMode() && !RogueClipMode())
00484   {
00485     DropClipPoint(nFlags, point);
00486   }
00487   else if (PathMode())
00488   {
00489     DropPathPoint(nFlags, point);
00490   }
00491   else OriginalButtonDown(nFlags, point);
00492 }
00493 
00494 void CXYWnd::OnMButtonDown(UINT nFlags, CPoint point) 
00495 {
00496   OriginalButtonDown(nFlags, point);
00497 }
00498 
00499 
00500 float Betwixt(float f1, float f2)
00501 {
00502   if (f1 > f2)
00503     return f2 + ((f1 - f2) / 2);
00504   else
00505     return f1 + ((f2 - f1) / 2);
00506 }
00507 
00508 void CXYWnd::ProduceSplits(brush_t** pFront, brush_t** pBack)
00509 {
00510   *pFront = NULL;
00511   *pBack = NULL;
00512   if (ClipMode())
00513   {
00514     if (g_Clip1.Set() && g_Clip2.Set())
00515     {
00516       face_t face;
00517       VectorCopy(g_Clip1.m_ptClip,face.planepts[0]);
00518       VectorCopy(g_Clip2.m_ptClip,face.planepts[1]);
00519       VectorCopy(g_Clip3.m_ptClip,face.planepts[2]);
00520       if (selected_brushes.next && (selected_brushes.next->next == &selected_brushes))
00521       {
00522         if (g_Clip3.Set() == false)
00523         {
00524           if (m_nViewType == XY)
00525           {
00526             face.planepts[0][2] = selected_brushes.next->mins[2];
00527             face.planepts[1][2] = selected_brushes.next->mins[2];
00528             face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
00529             face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
00530             face.planepts[2][2] = selected_brushes.next->maxs[2];
00531           }
00532           else if (m_nViewType == YZ)
00533           {
00534             face.planepts[0][0] = selected_brushes.next->mins[0];
00535             face.planepts[1][0] = selected_brushes.next->mins[0];
00536             face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
00537             face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
00538             face.planepts[2][0] = selected_brushes.next->maxs[0];
00539           }
00540           else
00541           {
00542             face.planepts[0][1] = selected_brushes.next->mins[1];
00543             face.planepts[1][1] = selected_brushes.next->mins[1];
00544             face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
00545             face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
00546             face.planepts[2][1] = selected_brushes.next->maxs[1];
00547           }
00548         }
00549 
00550         Brush_SplitBrushByFace (selected_brushes.next, &face, pFront, pBack);
00551       }
00552 
00553     }
00554   }
00555 }
00556 
00557 void CleanList(brush_t* pList)
00558 {
00559   brush_t* pBrush = pList->next; 
00560   while (pBrush != NULL && pBrush != pList)
00561   {
00562     brush_t* pNext = pBrush->next;
00563     Brush_Free(pBrush);
00564     pBrush = pNext;
00565   }
00566 }
00567 
00568 void CXYWnd::ProduceSplitLists()
00569 {
00570     if (AnyPatchesSelected())
00571     {
00572         Sys_Printf("Deslecting patches for clip operation.\n");
00573         brush_t *next;
00574         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = next)
00575         {
00576             next = pb->next;
00577             if (pb->patchBrush)
00578             {
00579                 Brush_RemoveFromList (pb);
00580                 Brush_AddToList (pb, &active_brushes);
00581                 UpdatePatchInspector();
00582             }
00583             if (pb->terrainBrush)
00584             {
00585                 Brush_RemoveFromList (pb);
00586                 Brush_AddToList (pb, &active_brushes);
00587                 UpdateTerrainInspector();
00588             }
00589         }
00590     }
00591 
00592     CleanList(&g_brFrontSplits);
00593     CleanList(&g_brBackSplits);
00594     g_brFrontSplits.next = &g_brFrontSplits;
00595     g_brBackSplits.next = &g_brBackSplits;
00596     brush_t* pBrush;
00597     for (pBrush = selected_brushes.next ; pBrush != NULL && pBrush != &selected_brushes ; pBrush=pBrush->next)
00598     {
00599         brush_t* pFront = NULL;
00600         brush_t* pBack = NULL;
00601         if (ClipMode())
00602         {
00603             if (g_Clip1.Set() && g_Clip2.Set())
00604             {
00605                 face_t face;
00606                 VectorCopy(g_Clip1.m_ptClip,face.planepts[0]);
00607                 VectorCopy(g_Clip2.m_ptClip,face.planepts[1]);
00608                 VectorCopy(g_Clip3.m_ptClip,face.planepts[2]);
00609                 if (g_Clip3.Set() == false)
00610                 {
00611                     if (g_pParentWnd->ActiveXY()->GetViewType() == XY)
00612                     {
00613                         face.planepts[0][2] = pBrush->mins[2];
00614                         face.planepts[1][2] = pBrush->mins[2];
00615                         face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
00616                         face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
00617                         face.planepts[2][2] = pBrush->maxs[2];
00618                     }
00619                     else if (g_pParentWnd->ActiveXY()->GetViewType() == YZ)
00620                     {
00621                         face.planepts[0][0] = pBrush->mins[0];
00622                         face.planepts[1][0] = pBrush->mins[0];
00623                         face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
00624                         face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
00625                         face.planepts[2][0] = pBrush->maxs[0];
00626                     }
00627                     else
00628                     {
00629                         face.planepts[0][1] = pBrush->mins[1];
00630                         face.planepts[1][1] = pBrush->mins[1];
00631                         face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
00632                         face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
00633                         face.planepts[2][1] = pBrush->maxs[1];
00634                     }
00635                 }
00636                 Brush_SplitBrushByFace (pBrush, &face, &pFront, &pBack);
00637                 if (pBack)
00638                     Brush_AddToList(pBack, &g_brBackSplits);
00639                 if (pFront)
00640                     Brush_AddToList(pFront, &g_brFrontSplits);
00641             }
00642         }
00643     }
00644 }
00645 
00646 void Brush_CopyList (brush_t* pFrom, brush_t* pTo)
00647 {
00648     brush_t* pBrush = pFrom->next; 
00649     while (pBrush != NULL && pBrush != pFrom)
00650     {
00651         brush_t* pNext = pBrush->next;
00652         Brush_RemoveFromList(pBrush);
00653         Brush_AddToList(pBrush, pTo);
00654         pBrush = pNext;
00655     }
00656 }
00657 
00658 void CXYWnd::OnRButtonDown(UINT nFlags, CPoint point) 
00659 {
00660   g_pParentWnd->SetActiveXY(this);
00661   m_ptDown = point;
00662   m_bRButtonDown = true;
00663 
00664   if (g_PrefsDlg.m_nMouseButtons == 3) // 3 button mouse 
00665   {
00666     if ((GetKeyState(VK_CONTROL) & 0x8000))
00667     {
00668       if (ClipMode()) // already there?
00669         DropClipPoint(nFlags, point);
00670       else
00671       {
00672         SetClipMode(true);
00673         g_bRogueClipMode = true;
00674         DropClipPoint(nFlags, point);
00675       }
00676       return;
00677     }
00678   }
00679   OriginalButtonDown(nFlags, point);
00680 }
00681 
00682 void CXYWnd::OnLButtonUp(UINT nFlags, CPoint point) 
00683 {
00684     // plugin entities
00685     if (DispatchOnLButtonUp(nFlags, point.x, point.y ))
00686         return;
00687 
00688     if (ClipMode())
00689   {
00690     if (g_pMovingClip)
00691     {
00692       ReleaseCapture();
00693       g_pMovingClip = NULL;
00694     }
00695   }
00696   OriginalButtonUp(nFlags, point);
00697 }
00698 
00699 void CXYWnd::OnMButtonUp(UINT nFlags, CPoint point) 
00700 {
00701   OriginalButtonUp(nFlags, point);
00702 }
00703 
00704 void CXYWnd::OnRButtonUp(UINT nFlags, CPoint point) 
00705 {
00706   m_bRButtonDown = false;
00707   if (point == m_ptDown)    // mouse didn't move
00708   {
00709     bool bGo = true;
00710     if ((GetKeyState(VK_MENU) & 0x8000))
00711       bGo = false;
00712     if ((GetKeyState(VK_CONTROL) & 0x8000))
00713       bGo = false;
00714     if ((GetKeyState(VK_SHIFT) & 0x8000))
00715       bGo = false;
00716     if (bGo)
00717       HandleDrop();
00718   }
00719   OriginalButtonUp(nFlags, point);
00720 }
00721 
00722 void CXYWnd::OriginalButtonDown(UINT nFlags, CPoint point)
00723 {
00724   CRect rctZ;
00725   GetClientRect(rctZ);
00726   SetWindowPos(&wndTop, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
00727   if (::GetTopWindow( g_qeglobals.d_hwndMain ) != GetSafeHwnd())
00728     ::BringWindowToTop(GetSafeHwnd());
00729     SetFocus();
00730     SetCapture();
00731     XY_MouseDown (point.x, rctZ.Height() - 1 - point.y , nFlags);
00732   m_nScrollFlags = nFlags;
00733 }          
00734 
00735 void CXYWnd::OriginalButtonUp(UINT nFlags, CPoint point)
00736 {
00737   CRect rctZ;
00738   GetClientRect(rctZ);
00739   XY_MouseUp (point.x, rctZ.Height() - 1 - point.y , nFlags);
00740     if (! (nFlags & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON)))
00741         ReleaseCapture ();
00742 }
00743 
00744 
00745 float fDiff(float f1, float f2)
00746 {
00747   if (f1 > f2)
00748     return f1 - f2;
00749   else
00750     return f2 - f1;
00751 }
00752 
00753 
00754 vec3_t tdp;
00755 void CXYWnd::OnMouseMove(UINT nFlags, CPoint point) 
00756 {
00757     // plugin entities
00758     //++timo TODO: handle return code
00759     DispatchOnMouseMove( nFlags, point.x, point.y );
00760 
00761   m_ptDown.x = 0;
00762   m_ptDown.y = 0;
00763 
00764   if ( g_PrefsDlg.m_bChaseMouse == TRUE &&
00765        (point.x < 0 || point.y < 0 || 
00766        point.x > m_nWidth || point.y > m_nHeight) &&
00767        GetCapture() == this)
00768   {
00769     float fAdjustment = (g_qeglobals.d_gridsize / 8 * 64) / m_fScale;
00770     //m_ptDrag = point;
00771     m_ptDragAdj.x = 0;
00772     m_ptDragAdj.y = 0;
00773     if (point.x < 0)
00774     {
00775       m_ptDragAdj.x = -fAdjustment;
00776     }
00777     else 
00778     if (point.x > m_nWidth)
00779     {
00780       m_ptDragAdj.x = fAdjustment;
00781     }
00782     if (point.y < 0)
00783     {
00784       m_ptDragAdj.y = -fAdjustment;
00785     }
00786     else
00787     if (point.y > m_nHeight)
00788     {
00789       m_ptDragAdj.y = fAdjustment;
00790     }
00791     if (m_nTimerID == -1)
00792     {
00793       m_nTimerID = SetTimer(100, 50, NULL);
00794       m_ptDrag = point;
00795       m_ptDragTotal = 0;
00796     }
00797     return;
00798   }
00799   //else if (m_nTimerID != -1)
00800   if (m_nTimerID != -1)
00801   {
00802     KillTimer(m_nTimerID);
00803     pressx -= m_ptDragTotal.x;
00804     pressy += m_ptDragTotal.y;
00805     m_nTimerID = -1;
00806     //return;
00807   }
00808 
00809   bool bCrossHair = false;
00810   if (!m_bRButtonDown)
00811   {
00812     tdp[0] = tdp[1] = tdp[2] = 0.0;
00813     SnapToPoint (point.x, m_nHeight - 1 - point.y , tdp);
00814 
00815     g_strStatus.Format("x:: %.1f  y:: %.1f  z:: %.1f", tdp[0], tdp[1], tdp[2]);
00816     g_pParentWnd->SetStatusText(1, g_strStatus);
00817 
00818     // i need to generalize the point code.. having 3 flavors pretty much sucks.. 
00819     // once the new curve stuff looks like it is going to stick i will 
00820     // rationalize this down to a single interface.. 
00821     if (PointMode())
00822     {
00823       if (g_pMovingPoint && GetCapture() == this)
00824       {
00825         bCrossHair = true;
00826         SnapToPoint (point.x, m_nHeight - 1 - point.y , g_pMovingPoint->m_ptClip);
00827         g_pMovingPoint->UpdatePointPtr();
00828         Sys_UpdateWindows(XY | W_CAMERA_IFON);
00829       }
00830       else
00831       {
00832         g_pMovingPoint = NULL;
00833         int nDim1 = (m_nViewType == YZ) ? 1 : 0;
00834         int nDim2 = (m_nViewType == XY) ? 1 : 2;
00835         for (int n = 0; n < g_nPointCount; n++)
00836         {
00837           if ( fDiff(g_PointPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 &&
00838                fDiff(g_PointPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3 )
00839           {
00840             bCrossHair = true;
00841             g_pMovingPoint = &g_PointPoints[n];
00842           }
00843         }
00844       }
00845     }
00846     else if (ClipMode())
00847     {
00848       if (g_pMovingClip && GetCapture() == this)
00849       {
00850         bCrossHair = true;
00851         SnapToPoint (point.x, m_nHeight - 1 - point.y , g_pMovingClip->m_ptClip);
00852         Sys_UpdateWindows(XY | W_CAMERA_IFON);
00853       }
00854       else
00855       {
00856         g_pMovingClip = NULL;
00857         int nDim1 = (m_nViewType == YZ) ? 1 : 0;
00858         int nDim2 = (m_nViewType == XY) ? 1 : 2;
00859         if (g_Clip1.Set())
00860         {
00861           if ( fDiff(g_Clip1.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
00862                fDiff(g_Clip1.m_ptClip[nDim2], tdp[nDim2]) < 3 )
00863           {
00864             bCrossHair = true;
00865             g_pMovingClip = &g_Clip1;
00866           }
00867         }
00868         if (g_Clip2.Set())
00869         {
00870           if ( fDiff(g_Clip2.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
00871                fDiff(g_Clip2.m_ptClip[nDim2], tdp[nDim2]) < 3 )
00872           {
00873             bCrossHair = true;
00874             g_pMovingClip = &g_Clip2;
00875           }
00876         }
00877         if (g_Clip3.Set())
00878         {
00879           if ( fDiff(g_Clip3.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
00880                fDiff(g_Clip3.m_ptClip[nDim2], tdp[nDim2]) < 3 )
00881           {
00882             bCrossHair = true;
00883             g_pMovingClip = &g_Clip3;
00884           }
00885         }
00886       }
00887       if (bCrossHair == false)
00888         XY_MouseMoved (point.x, m_nHeight - 1 - point.y , nFlags);
00889     }
00890     else if (PathMode())
00891     {
00892       if (g_pMovingPath && GetCapture() == this)
00893       {
00894         bCrossHair = true;
00895         SnapToPoint (point.x, m_nHeight - 1 - point.y , g_pMovingPath->m_ptClip);
00896         Sys_UpdateWindows(XY | W_CAMERA_IFON);
00897       }
00898       else
00899       {
00900         g_pMovingPath = NULL;
00901         int nDim1 = (m_nViewType == YZ) ? 1 : 0;
00902         int nDim2 = (m_nViewType == XY) ? 1 : 2;
00903         for (int n = 0; n < g_nPathCount; n++)
00904         {
00905           if ( fDiff(g_PathPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 &&
00906                fDiff(g_PathPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3 )
00907           {
00908             bCrossHair = true;
00909             g_pMovingPath = &g_PathPoints[n];
00910           }
00911         }
00912       }
00913     }
00914     else
00915     {
00916       XY_MouseMoved (point.x, m_nHeight - 1 - point.y , nFlags);
00917     }
00918   }
00919   else 
00920   {
00921     XY_MouseMoved (point.x, m_nHeight - 1 - point.y , nFlags);
00922   }
00923   if (bCrossHair)
00924     SetCursor(::LoadCursor(NULL, IDC_CROSS));
00925   else
00926     SetCursor(::LoadCursor(NULL, IDC_ARROW));
00927 }
00928 
00929 void CXYWnd::RetainClipMode(bool bMode)
00930 {
00931   bool bSave = g_bRogueClipMode;
00932   SetClipMode(bMode);
00933   if (bMode == true)
00934     g_bRogueClipMode = bSave;
00935   else
00936     g_bRogueClipMode = false;
00937 }
00938 
00939 void CXYWnd::SetClipMode(bool bMode)
00940 {
00941   g_bClipMode = bMode;
00942   g_bRogueClipMode = false;
00943   if (bMode)
00944   {
00945     g_Clip1.Reset();
00946     g_Clip2.Reset();
00947     g_Clip3.Reset();
00948     CleanList(&g_brFrontSplits);
00949     CleanList(&g_brBackSplits);
00950     g_brFrontSplits.next = &g_brFrontSplits;
00951     g_brBackSplits.next = &g_brBackSplits;
00952   }
00953   else
00954   {
00955     if (g_pMovingClip)
00956     {
00957       ReleaseCapture();
00958       g_pMovingClip = NULL;
00959     }
00960     CleanList(&g_brFrontSplits);
00961     CleanList(&g_brBackSplits);
00962     g_brFrontSplits.next = &g_brFrontSplits;
00963     g_brBackSplits.next = &g_brBackSplits;
00964     Sys_UpdateWindows(XY | W_CAMERA_IFON);
00965   }
00966 }
00967 
00968 bool CXYWnd::ClipMode()
00969 {
00970   return g_bClipMode;
00971 }
00972 
00973 bool CXYWnd::RogueClipMode()
00974 {
00975   return g_bRogueClipMode;
00976 }
00977 
00978 bool CXYWnd::PathMode()
00979 {
00980   return g_bPathMode;
00981 }
00982 
00983 
00984 bool CXYWnd::PointMode()
00985 {
00986   return g_bPointMode;
00987 }
00988 
00989 void CXYWnd::SetPointMode(bool b)
00990 {
00991   g_bPointMode = b;
00992   if (!b)
00993     g_nPointCount = 0;
00994 }
00995 
00996 
00997 void CXYWnd::OnPaint() 
00998 {
00999     CPaintDC dc(this); // device context for painting
01000   bool bPaint = true;
01001   if (!qwglMakeCurrent(dc.m_hDC, s_hglrcXY))
01002   {
01003     Sys_Printf("ERROR: wglMakeCurrent failed.. Error:%i\n",qglGetError());
01004     Sys_Printf("Please restart Q3Radiant if the Map view is not working\n");
01005     bPaint = false;
01006   }
01007   if (bPaint)
01008   {
01009     QE_CheckOpenGLForErrors();
01010         XY_Draw ();
01011     QE_CheckOpenGLForErrors();
01012 
01013     if (m_nViewType != XY)
01014     {
01015       qglPushMatrix();
01016       if (m_nViewType == YZ)
01017         qglRotatef (-90,  0, 1, 0);     // put Z going up
01018       qglRotatef (-90,  1, 0, 0);       // put Z going up
01019     }
01020  
01021     if (g_bCrossHairs)
01022     {
01023         qglColor4f(0.2, 0.9, 0.2, 0.8);
01024           qglBegin (GL_LINES);
01025       if (m_nViewType == XY)
01026       {
01027         qglVertex2f(-16384, tdp[1]);
01028         qglVertex2f(16384, tdp[1]);
01029         qglVertex2f(tdp[0], -16384);
01030         qglVertex2f(tdp[0], 16384);
01031       }
01032       else if (m_nViewType == YZ)
01033       {
01034         qglVertex3f(tdp[0], -16384, tdp[2]);
01035         qglVertex3f(tdp[0], 16384, tdp[2]);
01036         qglVertex3f(tdp[0], tdp[1], -16384);
01037         qglVertex3f(tdp[0], tdp[1], 16384);
01038       }
01039       else
01040       {
01041         qglVertex3f(-16384, tdp[1], tdp[2]);
01042         qglVertex3f( 16384, tdp[1], tdp[2]);
01043         qglVertex3f(tdp[0], tdp[1], -16384);
01044         qglVertex3f(tdp[0], tdp[1], 16384);
01045       }
01046           qglEnd();
01047     }
01048 
01049     if (ClipMode())
01050     {
01051       qglPointSize (4);
01052           qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER]);
01053           qglBegin (GL_POINTS);
01054       if (g_Clip1.Set())
01055               qglVertex3fv (g_Clip1);
01056       if (g_Clip2.Set())
01057               qglVertex3fv (g_Clip2);
01058       if (g_Clip3.Set())
01059               qglVertex3fv (g_Clip3);
01060           qglEnd ();
01061           qglPointSize (1);
01062 
01063       CString strMsg;
01064       if (g_Clip1.Set())
01065       {
01066         qglRasterPos3f (g_Clip1.m_ptClip[0]+2, g_Clip1.m_ptClip[1]+2, g_Clip1.m_ptClip[2]+2);
01067         strMsg = "1";
01068         //strMsg.Format("1 (%f, %f, %f)", g_Clip1[0], g_Clip1[1], g_Clip1[2]);
01069           qglCallLists (strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
01070       }
01071       if (g_Clip2.Set())
01072       {
01073         qglRasterPos3f (g_Clip2.m_ptClip[0]+2, g_Clip2.m_ptClip[1]+2, g_Clip2.m_ptClip[2]+2);
01074         strMsg = "2";
01075         //strMsg.Format("2 (%f, %f, %f)", g_Clip2[0], g_Clip2[1], g_Clip2[2]);
01076           qglCallLists (strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
01077       }
01078       if (g_Clip3.Set())
01079       {
01080         qglRasterPos3f (g_Clip3.m_ptClip[0]+2, g_Clip3.m_ptClip[1]+2, g_Clip3.m_ptClip[2]+2);
01081         strMsg = "3";
01082         //strMsg.Format("3 (%f, %f, %f)", g_Clip3[0], g_Clip3[1], g_Clip3[2]);
01083           qglCallLists (strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
01084       }
01085       if (g_Clip1.Set() && g_Clip2.Set())
01086       {
01087         ProduceSplitLists();
01088         brush_t* pBrush;
01089         brush_t* pList = ( (m_nViewType == XZ) ? !g_bSwitch : g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits;
01090           for (pBrush = pList->next ; pBrush != NULL && pBrush != pList ; pBrush=pBrush->next)
01091         {
01092               qglColor3f (1,1,0);
01093             face_t *face;
01094             int order;
01095             for (face = pBrush->brush_faces,order = 0 ; face ; face=face->next, order++)
01096             {
01097                 winding_t* w = face->face_winding;
01098                 if (!w)
01099                     continue;
01100                 // draw the polygon
01101                 qglBegin(GL_LINE_LOOP);
01102             for (int i=0 ; i<w->numpoints ; i++)
01103                   qglVertex3fv(w->points[i]);
01104                 qglEnd();
01105             }
01106         }
01107       }
01108 
01109     }
01110 
01111 
01112 
01113     if (PathMode())
01114     {
01115       qglPointSize (4);
01116           qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER]);
01117           qglBegin (GL_POINTS);
01118 
01119       for (int n = 0; n < g_nPathCount; n++)
01120         qglVertex3fv(g_PathPoints[n]);
01121           qglEnd ();
01122           qglPointSize (1);
01123 
01124       CString strMsg;
01125       for (n = 0; n < g_nPathCount; n++)
01126       {
01127         qglRasterPos3f (g_PathPoints[n].m_ptClip[0]+2, g_PathPoints[n].m_ptClip[1]+2, g_PathPoints[n].m_ptClip[2]+2);
01128         strMsg.Format("%i", n+1);
01129           qglCallLists (strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
01130       }
01131 
01132     }
01133     if (m_nViewType != XY)
01134       qglPopMatrix();
01135 
01136         qwglSwapBuffers(dc.m_hDC);
01137     TRACE("XY Paint\n");
01138   }
01139  }
01140 
01141 void CXYWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
01142 {
01143   g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags);
01144 }
01145 
01146 
01147 
01148 // FIXME: the brush_t *pBrush is never used. ( Entity_Create uses selected_brushes )
01149 void CreateEntityFromName(char* pName, brush_t* pBrush)
01150 {
01151     eclass_t *pecNew;
01152     entity_t *petNew;
01153     if (stricmp(pName, "worldspawn") == 0)
01154     {
01155         MessageBox(g_qeglobals.d_hwndMain, "Can't create an entity with worldspawn.", "info", 0);
01156         return;
01157     }
01158     
01159     pecNew = Eclass_ForName(pName, false);
01160     
01161     // create it
01162     petNew = Entity_Create(pecNew);
01163     if (petNew == NULL)
01164     {
01165         if (!((selected_brushes.next == &selected_brushes)||(selected_brushes.next->next != &selected_brushes)))
01166         {
01167             brush_t* b = selected_brushes.next;
01168             if (b->owner != world_entity && b->owner->eclass->fixedsize && pecNew->fixedsize)
01169             {
01170                 vec3_t mins, maxs;
01171                 vec3_t origin;
01172                 for (int i=0 ; i<3 ; i++)
01173                     origin[i] = b->mins[i] - pecNew->mins[i];
01174                 
01175                 VectorAdd (pecNew->mins, origin, mins);
01176                 VectorAdd (pecNew->maxs, origin, maxs);
01177                 brush_t* nb = Brush_Create (mins, maxs, &pecNew->texdef);
01178                 Entity_LinkBrush (b->owner, nb);
01179                 nb->owner->eclass = pecNew;
01180                 SetKeyValue (nb->owner, "classname", pName);
01181                 Brush_Free(b);
01182                 Brush_Build(nb);
01183                 Brush_AddToList (nb, &active_brushes);
01184                 Select_Brush(nb);
01185                 return;
01186             }
01187         }
01188         MessageBox(g_qeglobals.d_hwndMain, "Failed to create entity.", "info", 0);
01189         return;
01190     }
01191     
01192     Select_Deselect ();
01193     //entity_t* pEntity = world_entity;
01194     //if (selected_brushes.next != &selected_brushes)
01195     //  pEntity = selected_brushes.next->owner;
01196     Select_Brush (petNew->brushes.onext);
01197     
01198     if (stricmp(pName, "misc_model") == 0)
01199     {
01200         SetInspectorMode(W_ENTITY);
01201         PostMessage(g_qeglobals.d_hwndEntity, WM_COMMAND, IDC_BTN_ASSIGNMODEL, 0);
01202     }
01203     
01204 }
01205 
01206 
01207 brush_t* CreateEntityBrush(int x, int y, CXYWnd* pWnd)
01208 {
01209     vec3_t  mins, maxs;
01210     int     i;
01211     float   temp;
01212     brush_t *n;
01213 
01214     pWnd->SnapToPoint (x, y, mins);
01215   x += 32;
01216   y += 32;
01217     pWnd->SnapToPoint (x, y, maxs);
01218 
01219   int nDim = (pWnd->GetViewType() == XY) ? 2 : (pWnd->GetViewType() == YZ) ? 0 : 1;
01220     mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_z/g_qeglobals.d_gridsize));
01221     maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_z/g_qeglobals.d_gridsize));
01222 
01223   if (maxs[nDim] <= mins[nDim])
01224         maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize;
01225 
01226     for (i=0 ; i<3 ; i++)
01227     {
01228         if (mins[i] == maxs[i])
01229             maxs[i] += 16;  // don't create a degenerate brush
01230         if (mins[i] > maxs[i])
01231         {
01232             temp = mins[i];
01233             mins[i] = maxs[i];
01234             maxs[i] = temp;
01235         }
01236     }
01237 
01238     n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef);
01239     if (!n)
01240         return NULL;
01241 
01242     Brush_AddToList (n, &selected_brushes);
01243     Entity_LinkBrush (world_entity, n);
01244     Brush_Build( n );
01245   return n;
01246 }
01247 
01248 void CreateRightClickEntity(CXYWnd* pWnd, int x, int y, char* pName)
01249 {
01250   CRect rctZ;
01251   pWnd->GetClientRect(rctZ);
01252   brush_t* pBrush = (selected_brushes.next == &selected_brushes) ? CreateEntityBrush(x, rctZ.Height() - 1 - y, pWnd) : selected_brushes.next;
01253   CreateEntityFromName(pName, pBrush);
01254   //Select_Brush(pBrush);
01255 }
01256 
01257 brush_t* CreateSmartBrush(vec3_t v)
01258 {
01259     vec3_t  mins, maxs;
01260     int     i;
01261     brush_t *n;
01262 
01263     for (i=0 ; i<3 ; i++)
01264     {
01265     mins[i] = v[i] - 16;
01266     maxs[i] = v[i] + 16;
01267   }
01268 
01269     n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef);
01270     if (!n)
01271         return NULL;
01272 
01273     Brush_AddToList(n, &selected_brushes);
01274     //Entity_LinkBrush(world_entity, n);
01275     Brush_Build(n);
01276   return n;
01277 }
01278 
01279 
01280 
01281 
01282 CString g_strSmartEntity;
01283 int g_nSmartX;
01284 int g_nSmartY;
01285 bool g_bSmartWaiting;
01286 void _SmartPointDone(bool b, int n)
01287 {
01288   g_bSmartWaiting = false;
01289 }
01290 
01291 void CreateSmartEntity(CXYWnd* pWnd, int x, int y, const char* pName)
01292 {
01293   g_nSmartX = x;
01294   g_nSmartY = y;
01295   g_strSmartEntity = pName;
01296   if (g_strSmartEntity.Find("Smart_Train") >= 0)
01297   {
01298     ShowInfoDialog("Select the path of the train by left clicking in XY, YZ and/or XZ views. You can move an already dropped point by grabbing and moving it. When you are finished, press ENTER to accept and create the entity and path(s), press ESC to abandon the creation");
01299     g_bPathMode = true;
01300     g_nPathLimit = 0;
01301     g_nPathCount = 0;
01302     g_bSmartGo = true;
01303   }
01304   else
01305   if (g_strSmartEntity.Find("Smart_Monster...") >= 0)
01306   {
01307     g_bPathMode = true;
01308     g_nPathLimit = 0;
01309     g_nPathCount = 0;
01310   }
01311   else
01312   if (g_strSmartEntity.Find("Smart_Rotating") >= 0)
01313   {
01314     g_bSmartWaiting = true;
01315     ShowInfoDialog("Left click to specify the rotation origin");
01316     AcquirePath(1, &_SmartPointDone);
01317     while (g_bSmartWaiting)
01318     {
01319       MSG msg;
01320       if (::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )) 
01321       { 
01322         TranslateMessage(&msg);
01323         DispatchMessage(&msg);
01324       }
01325     }
01326     HideInfoDialog();
01327     CPtrArray array;
01328     g_bScreenUpdates = false;
01329     CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_rotating");
01330     array.Add(reinterpret_cast<void*>(selected_brushes.next));
01331     Select_Deselect();
01332     brush_t* pBrush = CreateSmartBrush(g_PathPoints[0]);
01333     array.Add(pBrush);
01334     Select_Deselect();
01335     Select_Brush(reinterpret_cast<brush_t*>(array.GetAt(0)));
01336     Select_Brush(reinterpret_cast<brush_t*>(array.GetAt(1)));
01337     ConnectEntities();
01338     g_bScreenUpdates = true;
01339   }
01340 }
01341 
01342 
01343 void FinishSmartCreation()
01344 {
01345   CPtrArray array;
01346   HideInfoDialog();
01347   brush_t* pEntities = NULL;
01348   if (g_strSmartEntity.Find("Smart_Train") >= 0)
01349   {
01350     g_bScreenUpdates = false;
01351     CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_train");
01352     array.Add(reinterpret_cast<void*>(selected_brushes.next));
01353     for (int n = 0; n < g_nPathCount; n++)
01354     {
01355       Select_Deselect();
01356       CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_PathPoints[n].m_ptScreen.x,g_PathPoints[n].m_ptScreen.y, "path_corner");
01357       array.Add(reinterpret_cast<void*>(selected_brushes.next));
01358     }
01359 
01360     for (n = 0; n < g_nPathCount; n++)
01361     {
01362       Select_Deselect();
01363       Select_Brush(reinterpret_cast<brush_t*>(array.GetAt(n)));
01364       Select_Brush(reinterpret_cast<brush_t*>(array.GetAt(n+1)));
01365       ConnectEntities();
01366     }
01367     g_bScreenUpdates = true;
01368 
01369   }
01370   g_nPathCount = 0;
01371   g_bPathMode = false;
01372   Sys_UpdateWindows(W_ALL);
01373 }
01374 
01375 void CXYWnd::KillPathMode()
01376 {
01377   g_bSmartGo = false;
01378   g_bPathMode = false;
01379   if (g_pPathFunc)
01380     g_pPathFunc(false, g_nPathCount);
01381   g_nPathCount = 0;
01382   g_pPathFunc = NULL;
01383   Sys_UpdateWindows(W_ALL);
01384 }
01385 
01386 // gets called for drop down menu messages
01387 // TIP: it's not