]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/vertsel.cpp
Merge pull request #19 from merlin1991/scons-update
[xonotic/netradiant.git] / radiant / vertsel.cpp
index 75b968e77998cb91a5cfbbf2477b08a1bed78440..886721ba77c9c0a40f621ef0b295a0471534db3c 100644 (file)
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*/\r
-\r
-#include "stdafx.h"\r
-//#include "qe3.h"\r
-#include "winding.h"\r
-\r
-int    FindPoint (vec3_t point)\r
-{\r
-       int             i, j;\r
-\r
-       for (i=0 ; i<g_qeglobals.d_numpoints ; i++)\r
-       {\r
-               for (j=0 ; j<3 ; j++)\r
-                       if (fabs(point[j] - g_qeglobals.d_points[i][j]) > 0.1)\r
-                               break;\r
-               if (j == 3)\r
-                       return i;\r
-       }\r
-\r
-       VectorCopy (point, g_qeglobals.d_points[g_qeglobals.d_numpoints]);\r
-       //qeglobals.d_points[g_qeglobals.d_numpoints] = point;\r
-  if (g_qeglobals.d_numpoints < MAX_POINTS-1)\r
-  {\r
-         g_qeglobals.d_numpoints++;\r
-  }\r
-\r
-       return g_qeglobals.d_numpoints-1;\r
-}\r
-\r
-//#define DBG_WNDG\r
-int FindEdge (int p1, int p2, face_t *f)\r
-{\r
-       int             i;\r
-\r
-       for (i=0 ; i<g_qeglobals.d_numedges ; i++)\r
-               if (g_qeglobals.d_edges[i].p1 == p2 && g_qeglobals.d_edges[i].p2 == p1)\r
-               {\r
-                       g_qeglobals.d_edges[i].f2 = f;\r
-#ifdef DBG_WNDG\r
-      Sys_Printf("g_qeglobals.d_edges[%d].f2 = %p\n", i, f);\r
-#endif\r
-                       return i;\r
-               }\r
-\r
-       g_qeglobals.d_edges[g_qeglobals.d_numedges].p1 = p1;\r
-       g_qeglobals.d_edges[g_qeglobals.d_numedges].p2 = p2;\r
-       g_qeglobals.d_edges[g_qeglobals.d_numedges].f1 = f;\r
-#ifdef DBG_WNDG\r
-  Sys_Printf("g_qeglobals.d_edges[%d].f1 = %p\n", g_qeglobals.d_numedges, f);\r
-#endif\r
-\r
-  if (g_qeglobals.d_numedges < MAX_EDGES-1)\r
-  {\r
-         g_qeglobals.d_numedges++;\r
-  }\r
-\r
-       return g_qeglobals.d_numedges-1;\r
-}\r
-\r
-void MakeFace (brush_t* b, face_t *f)\r
-{\r
-       winding_t       *w;\r
-       int                     i;\r
-       int                     pnum[128];\r
-\r
-       w = Brush_MakeFaceWinding (b, f);\r
-       if (!w)\r
-               return;\r
-       for (i=0 ; i<w->numpoints ; i++)\r
-               pnum[i] = FindPoint (w->points[i]);\r
-       for (i=0 ; i<w->numpoints ; i++)\r
-               FindEdge (pnum[i], pnum[(i+1)%w->numpoints], f);\r
-\r
-       free (w);\r
-}\r
-\r
-void SetupVertexSelection (void)\r
-{\r
-       face_t  *f;\r
-       brush_t *b;\r
-\r
-       g_qeglobals.d_numpoints = 0;\r
-       g_qeglobals.d_numedges = 0;\r
-\r
-       for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)\r
-       {\r
-               if (b->patchBrush || b->owner->eclass->fixedsize)\r
-                       continue; // don't make edge and vertex handles for patchbrushes\r
-               for (f=b->brush_faces ; f ; f=f->next)\r
-                       MakeFace (b,f);\r
-       }\r
-}\r
-\r
-void SelectFaceEdge (brush_t* b, face_t *f, int p1, int p2)\r
-{\r
-       winding_t       *w;\r
-       int                     i, j, k;\r
-       int                     pnum[128];\r
-\r
-#ifdef DBG_WNDG\r
-  if (f==NULL)\r
-    Sys_Printf("SelectFaceEdge %p %p\n", b, f);\r
-#endif\r
-\r
-       w = Winding_Clone(f->face_winding);//Brush_MakeFaceWinding (b, f);\r
-       if (!w)\r
-               return;\r
-       for (i=0 ; i<w->numpoints ; i++)\r
-               pnum[i] = FindPoint (w->points[i]);\r
-\r
-  for (i=0 ; i<w->numpoints ; i++)\r
-               if (pnum[i] == p1 && pnum[(i+1)%w->numpoints] == p2)\r
-               {\r
-                       VectorCopy (g_qeglobals.d_points[pnum[i]], f->planepts[0]);\r
-                       VectorCopy (g_qeglobals.d_points[pnum[(i+1)%w->numpoints]], f->planepts[1]);\r
-                       VectorCopy (g_qeglobals.d_points[pnum[(i+2)%w->numpoints]], f->planepts[2]);\r
-                       for (j=0 ; j<3 ; j++)\r
-                       {\r
-                               for (k=0 ; k<3 ; k++)\r
-                               {\r
-                                       f->planepts[j][k] = floor(f->planepts[j][k]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;\r
-                               }\r
-                       }\r
-\r
-                       AddPlanept (f->planepts[0]);\r
-                       AddPlanept (f->planepts[1]);\r
-                       break;\r
-               }\r
-\r
-       if (i == w->numpoints)\r
-               Sys_Printf ("SelectFaceEdge: failed\n");\r
-       Winding_Free (w);\r
-}\r
-\r
-\r
-void SelectVertex (int p1)\r
-{\r
-       brush_t         *b;\r
-       winding_t       *w;\r
-       int             i;\r
-       face_t          *f;\r
-\r
-       for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)\r
-  {\r
-         for (f=b->brush_faces ; f ; f=f->next)\r
-         {\r
-                 w =  Brush_MakeFaceWinding (b, f);\r
-                 if (!w)\r
-                         continue;\r
-                 for (i=0 ; i<w->numpoints ; i++)\r
-                 {\r
-                         if (FindPoint (w->points[i]) == p1)\r
-                         {\r
-                                 VectorCopy (w->points[(i+w->numpoints-1)%w->numpoints], f->planepts[0]);\r
-                                 VectorCopy (w->points[i], f->planepts[1]);\r
-                                 VectorCopy (w->points[(i+1)%w->numpoints], f->planepts[2]);\r
-          // NOTE: used to be a planepts clamping to grid here\r
-\r
-                           AddPlanept (f->planepts[1]);\r
-\r
-                           break;\r
-        }\r
-                 }\r
-                 free (w);\r
-         }\r
-  }\r
-}\r
-\r
-#define SELECT_EPSILON 8\r
-\r
-void SelectVertexByRay (vec3_t org, vec3_t dir)\r
-{\r
-       int             i, besti;\r
-       float   d, bestd = VEC_MAX;\r
-  vec_t epsilon, divergence;\r
-  ray_t ray;\r
-  ray_construct_for_vec3(&ray, org, dir);\r
-\r
-       // find the point closest to the ray\r
-       besti = -1;\r
-       if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord)\r
-               && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view\r
-  {\r
-    divergence = 0;\r
-               epsilon = SELECT_EPSILON /  g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level\r
-  }\r
-  else\r
-  {\r
-    divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length\r
-    epsilon = 0;\r
-  }\r
-\r
-       for (i=0 ; i<g_qeglobals.d_numpoints ; i++)\r
-       {\r
-               d = ray_intersect_point(&ray, g_qeglobals.d_points[i], epsilon, divergence);\r
-\r
-               if (d < bestd)\r
-               {\r
-                       bestd = d;\r
-                       besti = i;\r
-               }\r
-       }\r
-\r
-       if (besti == -1)\r
-       {\r
-               Sys_Printf ("Click didn't hit a vertex\n");\r
-               return;\r
-       }\r
-       Sys_Printf ("hit vertex\n");\r
-       g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = g_qeglobals.d_points[besti];\r
-       if (!g_PrefsDlg.m_bVertexSplit)\r
-  {\r
-         SelectVertex (besti);\r
-  }\r
-}\r
-\r
-// TTimo: NOTE: we should not have to put extern funcs like that\r
-//   those should be defined in qe3.h\r
-extern void AddPatchMovePoint(vec3_t v, bool bMulti, bool bFull);\r
-extern int PointInMoveList(float *pf);\r
-void SelectCurvePointByRay (vec3_t org, vec3_t dir, int buttons)\r
-{\r
-       int             i, j;\r
-       float   d, bestd = VEC_MAX;\r
-       vec3_t  *pPointBest;\r
-  vec_t epsilon, divergence;\r
-  ray_t ray;\r
-  ray_construct_for_vec3(&ray, org, dir);\r
-\r
-       // find the point closest to the ray\r
-       pPointBest = NULL;\r
-       if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord)\r
-               && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view\r
-  {\r
-    divergence = 0;\r
-               epsilon = SELECT_EPSILON /  g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level\r
-  }\r
-  else\r
-  {\r
-    divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length\r
-    epsilon = 0;\r
-  }\r
-\r
-\r
-       g_qeglobals.d_numpoints = 0;\r
-\r
-       for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)\r
-       {\r
-               if (pb->patchBrush)\r
-               {\r
-                       patchMesh_t* p = pb->pPatch;\r
-                       \r
-                       for (i = 0 ; i < p->width ; i++ ) \r
-                       {\r
-                               for ( j = 0 ; j < p->height ; j++ )\r
-                               {\r
-          d = ray_intersect_point(&ray, p->ctrl[i][j].xyz, epsilon, divergence);\r
-\r
-                                       if (d >= bestd)\r
-                                               continue;\r
-                                       \r
-                                       bestd = d;\r
-\r
-                                       if (PointInMoveList(*pPointBest) != -1 && PointInMoveList(p->ctrl[i][j].xyz) == -1)\r
-                                               continue; // choose selected points with preference over unselected\r
-\r
-                                       pPointBest = &p->ctrl[i][j].xyz;\r
-                                       \r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       if (pPointBest == NULL)\r
-       {\r
-               if (g_pParentWnd->ActiveXY()->AreaSelectOK())\r
-               {\r
-                       g_qeglobals.d_select_mode = sel_area;\r
-                       VectorCopy(org, g_qeglobals.d_vAreaTL);\r
-                       VectorCopy(org, g_qeglobals.d_vAreaBR);\r
-               }\r
-               return;\r
-       }\r
-       else\r
-               AddPatchMovePoint(pPointBest[0], buttons & MK_CONTROL, buttons & MK_SHIFT);\r
-}\r
-\r
-// optimization bug:\r
-// had to use the #define DBG_WNDG to identify\r
-// the first loop that checks the best edge is broken in release-optimized build\r
-// unrolled the mid[] loop and forced floating consistency on seems to fix\r
-#ifdef _WIN32\r
-#pragma optimize( "p", on )\r
-#endif\r
-void SelectEdgeByRay (vec3_t org, vec3_t dir)\r
-{\r
-       int             i, besti;\r
-       float   d, bestd = VEC_MAX;\r
-       vec3_t  mid;\r
-       pedge_t *e;\r
-  vec_t epsilon, divergence;\r
-  ray_t ray;\r
-  ray_construct_for_vec3(&ray, org, dir);\r
-\r
-       // find the edge closest to the ray\r
-       besti = -1;\r
-       if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord)\r
-               && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view\r
-  {\r
-    divergence = 0;\r
-               epsilon = SELECT_EPSILON /  g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level\r
-  }\r
-  else\r
-  {\r
-    divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length\r
-    epsilon = 0;\r
-  }\r
-\r
-       for (i=0 ; i<g_qeglobals.d_numedges ; i++)\r
-       {\r
-    mid[0] = 0.5f*(g_qeglobals.d_points[g_qeglobals.d_edges[i].p1][0] + g_qeglobals.d_points[g_qeglobals.d_edges[i].p2][0]);\r
-    mid[1] = 0.5f*(g_qeglobals.d_points[g_qeglobals.d_edges[i].p1][1] + g_qeglobals.d_points[g_qeglobals.d_edges[i].p2][1]);\r
-    mid[2] = 0.5f*(g_qeglobals.d_points[g_qeglobals.d_edges[i].p1][2] + g_qeglobals.d_points[g_qeglobals.d_edges[i].p2][2]);\r
-\r
-               d = ray_intersect_point(&ray, mid, epsilon, divergence);\r
-\r
-#ifdef DBG_WNDG\r
-    Sys_Printf("d: %f\n", d);\r
-#endif\r
-               if (d < bestd)\r
-               {\r
-#ifdef DBG_WNDG\r
-      Sys_Printf("bestd = d\n");\r
-#endif\r
-                       bestd = d;\r
-                       besti = i;\r
-               }\r
-       }\r
-\r
-       if (besti == -1)\r
-       {\r
-               Sys_Printf ("Click didn't hit an edge\n");\r
-               return;\r
-       }\r
-       Sys_Printf ("Hit edge\n");\r
-\r
-       // make the two faces that border the edge use the two edge points\r
-       // as primary drag points\r
-       g_qeglobals.d_num_move_points = 0;\r
-       e = &g_qeglobals.d_edges[besti];\r
-#ifdef DBG_WNDG\r
-  Sys_Printf("besti: %d\n", besti);\r
-  if (e->f1 == NULL)\r
-  {\r
-    Sys_Printf ("e->f1 == NULL e->f2 %p\n", e->f2);\r
-  }\r
-  if (e->f2 == NULL)\r
-  {\r
-    Sys_Printf ("e->f1 %p e->f2 == NULL\n",e->f1);\r
-  }\r
-#endif\r
-       for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next)\r
-  {\r
-    SelectFaceEdge (b, e->f1, e->p1, e->p2);\r
-         SelectFaceEdge (b, e->f2, e->p2, e->p1);\r
-  }\r
-}\r
+/*
+   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
+ */
+
+#include "stdafx.h"
+//#include "qe3.h"
+#include "winding.h"
+
+int FindPoint( vec3_t point ){
+       int i, j;
+
+       for ( i = 0 ; i < g_qeglobals.d_numpoints ; i++ )
+       {
+               for ( j = 0 ; j < 3 ; j++ )
+                       if ( fabs( point[j] - g_qeglobals.d_points[i][j] ) > 0.1 ) {
+                               break;
+                       }
+               if ( j == 3 ) {
+                       return i;
+               }
+       }
+
+       VectorCopy( point, g_qeglobals.d_points[g_qeglobals.d_numpoints] );
+       //qeglobals.d_points[g_qeglobals.d_numpoints] = point;
+       if ( g_qeglobals.d_numpoints < MAX_POINTS - 1 ) {
+               g_qeglobals.d_numpoints++;
+       }
+
+       return g_qeglobals.d_numpoints - 1;
+}
+
+//#define DBG_WNDG
+int FindEdge( int p1, int p2, face_t *f ){
+       int i;
+
+       for ( i = 0 ; i < g_qeglobals.d_numedges ; i++ )
+               if ( g_qeglobals.d_edges[i].p1 == p2 && g_qeglobals.d_edges[i].p2 == p1 ) {
+                       g_qeglobals.d_edges[i].f2 = f;
+#ifdef DBG_WNDG
+                       Sys_Printf( "g_qeglobals.d_edges[%d].f2 = %p\n", i, f );
+#endif
+                       return i;
+               }
+
+       g_qeglobals.d_edges[g_qeglobals.d_numedges].p1 = p1;
+       g_qeglobals.d_edges[g_qeglobals.d_numedges].p2 = p2;
+       g_qeglobals.d_edges[g_qeglobals.d_numedges].f1 = f;
+#ifdef DBG_WNDG
+       Sys_Printf( "g_qeglobals.d_edges[%d].f1 = %p\n", g_qeglobals.d_numedges, f );
+#endif
+
+       if ( g_qeglobals.d_numedges < MAX_EDGES - 1 ) {
+               g_qeglobals.d_numedges++;
+       }
+
+       return g_qeglobals.d_numedges - 1;
+}
+
+void MakeFace( brush_t* b, face_t *f ){
+       winding_t   *w;
+       int i;
+       int pnum[128];
+
+       w = Brush_MakeFaceWinding( b, f );
+       if ( !w ) {
+               return;
+       }
+       for ( i = 0 ; i < w->numpoints ; i++ )
+               pnum[i] = FindPoint( w->points[i] );
+       for ( i = 0 ; i < w->numpoints ; i++ )
+               FindEdge( pnum[i], pnum[( i + 1 ) % w->numpoints], f );
+
+       free( w );
+}
+
+void SetupVertexSelection( void ){
+       face_t  *f;
+       brush_t *b;
+
+       g_qeglobals.d_numpoints = 0;
+       g_qeglobals.d_numedges = 0;
+
+       for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
+       {
+               if ( b->patchBrush || b->owner->eclass->fixedsize ) {
+                       continue; // don't make edge and vertex handles for patchbrushes
+               }
+               for ( f = b->brush_faces ; f ; f = f->next )
+                       MakeFace( b,f );
+       }
+}
+
+void SelectFaceEdge( brush_t* b, face_t *f, int p1, int p2 ){
+       winding_t   *w;
+       int i, j, k;
+       int pnum[128];
+
+#ifdef DBG_WNDG
+       if ( f == NULL ) {
+               Sys_Printf( "SelectFaceEdge %p %p\n", b, f );
+       }
+#endif
+
+       w = Winding_Clone( f->face_winding ); //Brush_MakeFaceWinding (b, f);
+       if ( !w ) {
+               return;
+       }
+       for ( i = 0 ; i < w->numpoints ; i++ )
+               pnum[i] = FindPoint( w->points[i] );
+
+       for ( i = 0 ; i < w->numpoints ; i++ )
+               if ( pnum[i] == p1 && pnum[( i + 1 ) % w->numpoints] == p2 ) {
+                       VectorCopy( g_qeglobals.d_points[pnum[i]], f->planepts[0] );
+                       VectorCopy( g_qeglobals.d_points[pnum[( i + 1 ) % w->numpoints]], f->planepts[1] );
+                       VectorCopy( g_qeglobals.d_points[pnum[( i + 2 ) % w->numpoints]], f->planepts[2] );
+                       for ( j = 0 ; j < 3 ; j++ )
+                       {
+                               for ( k = 0 ; k < 3 ; k++ )
+                               {
+                                       f->planepts[j][k] = floor( f->planepts[j][k] / g_qeglobals.d_gridsize + 0.5 ) * g_qeglobals.d_gridsize;
+                               }
+                       }
+
+                       AddPlanept( f->planepts[0] );
+                       AddPlanept( f->planepts[1] );
+                       break;
+               }
+
+       if ( i == w->numpoints ) {
+               Sys_Printf( "SelectFaceEdge: failed\n" );
+       }
+       Winding_Free( w );
+}
+
+
+void SelectVertex( int p1 ){
+       brush_t     *b;
+       winding_t   *w;
+       int i;
+       face_t      *f;
+
+       for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
+       {
+               for ( f = b->brush_faces ; f ; f = f->next )
+               {
+                       w =  Brush_MakeFaceWinding( b, f );
+                       if ( !w ) {
+                               continue;
+                       }
+                       for ( i = 0 ; i < w->numpoints ; i++ )
+                       {
+                               if ( FindPoint( w->points[i] ) == p1 ) {
+                                       VectorCopy( w->points[( i + w->numpoints - 1 ) % w->numpoints], f->planepts[0] );
+                                       VectorCopy( w->points[i], f->planepts[1] );
+                                       VectorCopy( w->points[( i + 1 ) % w->numpoints], f->planepts[2] );
+                                       // NOTE: used to be a planepts clamping to grid here
+
+                                       AddPlanept( f->planepts[1] );
+
+                                       break;
+                               }
+                       }
+                       free( w );
+               }
+       }
+}
+
+#define SELECT_EPSILON 8
+
+void SelectVertexByRay( vec3_t org, vec3_t dir ){
+       int i, besti;
+       float d, bestd = VEC_MAX;
+       vec_t epsilon, divergence;
+       ray_t ray;
+       ray_construct_for_vec3( &ray, org, dir );
+
+       // find the point closest to the ray
+       besti = -1;
+       if ( ( fabs( org[0] ) == g_MaxWorldCoord || fabs( org[1] ) == g_MaxWorldCoord || fabs( org[2] ) == g_MaxWorldCoord )
+                && ( fabs( dir[0] ) == 1.0f || fabs( dir[1] ) == 1.0f || fabs( dir[2] ) == 1.0f ) ) { // very unlikely unless 2d view
+               divergence = 0;
+               epsilon = SELECT_EPSILON /  g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level
+       }
+       else
+       {
+               divergence = SELECT_EPSILON / ( g_pParentWnd->GetCamWnd()->Camera()->width * 0.5 ); // radius / focal length
+               epsilon = 0;
+       }
+
+       for ( i = 0 ; i < g_qeglobals.d_numpoints ; i++ )
+       {
+               d = ray_intersect_point( &ray, g_qeglobals.d_points[i], epsilon, divergence );
+
+               if ( d < bestd ) {
+                       bestd = d;
+                       besti = i;
+               }
+       }
+
+       if ( besti == -1 ) {
+               Sys_Printf( "Click didn't hit a vertex\n" );
+               return;
+       }
+       Sys_Printf( "hit vertex\n" );
+       g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = g_qeglobals.d_points[besti];
+       if ( !g_PrefsDlg.m_bVertexSplit ) {
+               SelectVertex( besti );
+       }
+}
+
+// TTimo: NOTE: we should not have to put extern funcs like that
+//   those should be defined in qe3.h
+extern void AddPatchMovePoint( vec3_t v, bool bMulti, bool bFull );
+extern int PointInMoveList( float *pf );
+void SelectCurvePointByRay( vec3_t org, vec3_t dir, int buttons ){
+       int i, j;
+       float d, bestd = VEC_MAX;
+       vec3_t  *pPointBest;
+       vec_t epsilon, divergence;
+       ray_t ray;
+       ray_construct_for_vec3( &ray, org, dir );
+
+       // find the point closest to the ray
+       pPointBest = NULL;
+       if ( ( fabs( org[0] ) == g_MaxWorldCoord || fabs( org[1] ) == g_MaxWorldCoord || fabs( org[2] ) == g_MaxWorldCoord )
+                && ( fabs( dir[0] ) == 1.0f || fabs( dir[1] ) == 1.0f || fabs( dir[2] ) == 1.0f ) ) { // very unlikely unless 2d view
+               divergence = 0;
+               epsilon = SELECT_EPSILON /  g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level
+       }
+       else
+       {
+               divergence = SELECT_EPSILON / ( g_pParentWnd->GetCamWnd()->Camera()->width * 0.5 ); // radius / focal length
+               epsilon = 0;
+       }
+
+
+       g_qeglobals.d_numpoints = 0;
+
+       for ( brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next )
+       {
+               if ( pb->patchBrush ) {
+                       patchMesh_t* p = pb->pPatch;
+
+                       for ( i = 0 ; i < p->width ; i++ )
+                       {
+                               for ( j = 0 ; j < p->height ; j++ )
+                               {
+                                       d = ray_intersect_point( &ray, p->ctrl[i][j].xyz, epsilon, divergence );
+
+                                       if ( d >= bestd ) {
+                                               continue;
+                                       }
+
+                                       bestd = d;
+
+                                       if ( PointInMoveList( *pPointBest ) != -1 && PointInMoveList( p->ctrl[i][j].xyz ) == -1 ) {
+                                               continue; // choose selected points with preference over unselected
+
+                                       }
+                                       pPointBest = &p->ctrl[i][j].xyz;
+
+                               }
+                       }
+               }
+       }
+
+       if ( pPointBest == NULL ) {
+               if ( g_pParentWnd->ActiveXY()->AreaSelectOK() ) {
+                       g_qeglobals.d_select_mode = sel_area;
+                       VectorCopy( org, g_qeglobals.d_vAreaTL );
+                       VectorCopy( org, g_qeglobals.d_vAreaBR );
+               }
+               return;
+       }
+       else{
+               AddPatchMovePoint( pPointBest[0], buttons & MK_CONTROL, buttons & MK_SHIFT );
+       }
+}
+
+// optimization bug:
+// had to use the #define DBG_WNDG to identify
+// the first loop that checks the best edge is broken in release-optimized build
+// unrolled the mid[] loop and forced floating consistency on seems to fix
+#ifdef _WIN32
+#pragma optimize( "p", on )
+#endif
+void SelectEdgeByRay( vec3_t org, vec3_t dir ){
+       int i, besti;
+       float d, bestd = VEC_MAX;
+       vec3_t mid;
+       pedge_t *e;
+       vec_t epsilon, divergence;
+       ray_t ray;
+       ray_construct_for_vec3( &ray, org, dir );
+
+       // find the edge closest to the ray
+       besti = -1;
+       if ( ( fabs( org[0] ) == g_MaxWorldCoord || fabs( org[1] ) == g_MaxWorldCoord || fabs( org[2] ) == g_MaxWorldCoord )
+                && ( fabs( dir[0] ) == 1.0f || fabs( dir[1] ) == 1.0f || fabs( dir[2] ) == 1.0f ) ) { // very unlikely unless 2d view
+               divergence = 0;
+               epsilon = SELECT_EPSILON /  g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level
+       }
+       else
+       {
+               divergence = SELECT_EPSILON / ( g_pParentWnd->GetCamWnd()->Camera()->width * 0.5 ); // radius / focal length
+               epsilon = 0;
+       }
+
+       for ( i = 0 ; i < g_qeglobals.d_numedges ; i++ )
+       {
+               mid[0] = 0.5f * ( g_qeglobals.d_points[g_qeglobals.d_edges[i].p1][0] + g_qeglobals.d_points[g_qeglobals.d_edges[i].p2][0] );
+               mid[1] = 0.5f * ( g_qeglobals.d_points[g_qeglobals.d_edges[i].p1][1] + g_qeglobals.d_points[g_qeglobals.d_edges[i].p2][1] );
+               mid[2] = 0.5f * ( g_qeglobals.d_points[g_qeglobals.d_edges[i].p1][2] + g_qeglobals.d_points[g_qeglobals.d_edges[i].p2][2] );
+
+               d = ray_intersect_point( &ray, mid, epsilon, divergence );
+
+#ifdef DBG_WNDG
+               Sys_Printf( "d: %f\n", d );
+#endif
+               if ( d < bestd ) {
+#ifdef DBG_WNDG
+                       Sys_Printf( "bestd = d\n" );
+#endif
+                       bestd = d;
+                       besti = i;
+               }
+       }
+
+       if ( besti == -1 ) {
+               Sys_Printf( "Click didn't hit an edge\n" );
+               return;
+       }
+       Sys_Printf( "Hit edge\n" );
+
+       // make the two faces that border the edge use the two edge points
+       // as primary drag points
+       g_qeglobals.d_num_move_points = 0;
+       e = &g_qeglobals.d_edges[besti];
+#ifdef DBG_WNDG
+       Sys_Printf( "besti: %d\n", besti );
+       if ( e->f1 == NULL ) {
+               Sys_Printf( "e->f1 == NULL e->f2 %p\n", e->f2 );
+       }
+       if ( e->f2 == NULL ) {
+               Sys_Printf( "e->f1 %p e->f2 == NULL\n",e->f1 );
+       }
+#endif
+       for ( brush_t* b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
+       {
+               SelectFaceEdge( b, e->f1, e->p1, e->p2 );
+               SelectFaceEdge( b, e->f2, e->p2, e->p1 );
+       }
+}