]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/vertsel.cpp
create a branch for AB sync
[xonotic/netradiant.git] / radiant / vertsel.cpp
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 */\r
21 \r
22 #include "stdafx.h"\r
23 //#include "qe3.h"\r
24 #include "winding.h"\r
25 \r
26 int     FindPoint (vec3_t point)\r
27 {\r
28         int             i, j;\r
29 \r
30         for (i=0 ; i<g_qeglobals.d_numpoints ; i++)\r
31         {\r
32                 for (j=0 ; j<3 ; j++)\r
33                         if (fabs(point[j] - g_qeglobals.d_points[i][j]) > 0.1)\r
34                                 break;\r
35                 if (j == 3)\r
36                         return i;\r
37         }\r
38 \r
39         VectorCopy (point, g_qeglobals.d_points[g_qeglobals.d_numpoints]);\r
40         //qeglobals.d_points[g_qeglobals.d_numpoints] = point;\r
41   if (g_qeglobals.d_numpoints < MAX_POINTS-1)\r
42   {\r
43           g_qeglobals.d_numpoints++;\r
44   }\r
45 \r
46         return g_qeglobals.d_numpoints-1;\r
47 }\r
48 \r
49 //#define DBG_WNDG\r
50 int FindEdge (int p1, int p2, face_t *f)\r
51 {\r
52         int             i;\r
53 \r
54         for (i=0 ; i<g_qeglobals.d_numedges ; i++)\r
55                 if (g_qeglobals.d_edges[i].p1 == p2 && g_qeglobals.d_edges[i].p2 == p1)\r
56                 {\r
57                         g_qeglobals.d_edges[i].f2 = f;\r
58 #ifdef DBG_WNDG\r
59       Sys_Printf("g_qeglobals.d_edges[%d].f2 = %p\n", i, f);\r
60 #endif\r
61                         return i;\r
62                 }\r
63 \r
64         g_qeglobals.d_edges[g_qeglobals.d_numedges].p1 = p1;\r
65         g_qeglobals.d_edges[g_qeglobals.d_numedges].p2 = p2;\r
66         g_qeglobals.d_edges[g_qeglobals.d_numedges].f1 = f;\r
67 #ifdef DBG_WNDG\r
68   Sys_Printf("g_qeglobals.d_edges[%d].f1 = %p\n", g_qeglobals.d_numedges, f);\r
69 #endif\r
70 \r
71   if (g_qeglobals.d_numedges < MAX_EDGES-1)\r
72   {\r
73           g_qeglobals.d_numedges++;\r
74   }\r
75 \r
76         return g_qeglobals.d_numedges-1;\r
77 }\r
78 \r
79 void MakeFace (brush_t* b, face_t *f)\r
80 {\r
81         winding_t       *w;\r
82         int                     i;\r
83         int                     pnum[128];\r
84 \r
85         w = Brush_MakeFaceWinding (b, f);\r
86         if (!w)\r
87                 return;\r
88         for (i=0 ; i<w->numpoints ; i++)\r
89                 pnum[i] = FindPoint (w->points[i]);\r
90         for (i=0 ; i<w->numpoints ; i++)\r
91                 FindEdge (pnum[i], pnum[(i+1)%w->numpoints], f);\r
92 \r
93         free (w);\r
94 }\r
95 \r
96 void SetupVertexSelection (void)\r
97 {\r
98         face_t  *f;\r
99         brush_t *b;\r
100 \r
101         g_qeglobals.d_numpoints = 0;\r
102         g_qeglobals.d_numedges = 0;\r
103 \r
104         for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)\r
105         {\r
106                 if (b->patchBrush || b->owner->eclass->fixedsize)\r
107                         continue; // don't make edge and vertex handles for patchbrushes\r
108                 for (f=b->brush_faces ; f ; f=f->next)\r
109                         MakeFace (b,f);\r
110         }\r
111 }\r
112 \r
113 void SelectFaceEdge (brush_t* b, face_t *f, int p1, int p2)\r
114 {\r
115         winding_t       *w;\r
116         int                     i, j, k;\r
117         int                     pnum[128];\r
118 \r
119 #ifdef DBG_WNDG\r
120   if (f==NULL)\r
121     Sys_Printf("SelectFaceEdge %p %p\n", b, f);\r
122 #endif\r
123 \r
124         w = Winding_Clone(f->face_winding);//Brush_MakeFaceWinding (b, f);\r
125         if (!w)\r
126                 return;\r
127         for (i=0 ; i<w->numpoints ; i++)\r
128                 pnum[i] = FindPoint (w->points[i]);\r
129 \r
130   for (i=0 ; i<w->numpoints ; i++)\r
131                 if (pnum[i] == p1 && pnum[(i+1)%w->numpoints] == p2)\r
132                 {\r
133                         VectorCopy (g_qeglobals.d_points[pnum[i]], f->planepts[0]);\r
134                         VectorCopy (g_qeglobals.d_points[pnum[(i+1)%w->numpoints]], f->planepts[1]);\r
135                         VectorCopy (g_qeglobals.d_points[pnum[(i+2)%w->numpoints]], f->planepts[2]);\r
136                         for (j=0 ; j<3 ; j++)\r
137                         {\r
138                                 for (k=0 ; k<3 ; k++)\r
139                                 {\r
140                                         f->planepts[j][k] = floor(f->planepts[j][k]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;\r
141                                 }\r
142                         }\r
143 \r
144                         AddPlanept (f->planepts[0]);\r
145                         AddPlanept (f->planepts[1]);\r
146                         break;\r
147                 }\r
148 \r
149         if (i == w->numpoints)\r
150                 Sys_Printf ("SelectFaceEdge: failed\n");\r
151         Winding_Free (w);\r
152 }\r
153 \r
154 \r
155 void SelectVertex (int p1)\r
156 {\r
157         brush_t         *b;\r
158         winding_t       *w;\r
159         int             i;\r
160         face_t          *f;\r
161 \r
162         for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)\r
163   {\r
164           for (f=b->brush_faces ; f ; f=f->next)\r
165           {\r
166                   w =  Brush_MakeFaceWinding (b, f);\r
167                   if (!w)\r
168                           continue;\r
169                   for (i=0 ; i<w->numpoints ; i++)\r
170                   {\r
171                           if (FindPoint (w->points[i]) == p1)\r
172                           {\r
173                                   VectorCopy (w->points[(i+w->numpoints-1)%w->numpoints], f->planepts[0]);\r
174                                   VectorCopy (w->points[i], f->planepts[1]);\r
175                                   VectorCopy (w->points[(i+1)%w->numpoints], f->planepts[2]);\r
176           // NOTE: used to be a planepts clamping to grid here\r
177 \r
178                             AddPlanept (f->planepts[1]);\r
179 \r
180                             break;\r
181         }\r
182                   }\r
183                   free (w);\r
184           }\r
185   }\r
186 }\r
187 \r
188 #define SELECT_EPSILON 8\r
189 \r
190 void SelectVertexByRay (vec3_t org, vec3_t dir)\r
191 {\r
192         int             i, besti;\r
193         float   d, bestd = VEC_MAX;\r
194   vec_t epsilon, divergence;\r
195   ray_t ray;\r
196   ray_construct_for_vec3(&ray, org, dir);\r
197 \r
198         // find the point closest to the ray\r
199         besti = -1;\r
200         if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord)\r
201                 && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view\r
202   {\r
203     divergence = 0;\r
204                 epsilon = SELECT_EPSILON /  g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level\r
205   }\r
206   else\r
207   {\r
208     divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length\r
209     epsilon = 0;\r
210   }\r
211 \r
212         for (i=0 ; i<g_qeglobals.d_numpoints ; i++)\r
213         {\r
214                 d = ray_intersect_point(&ray, g_qeglobals.d_points[i], epsilon, divergence);\r
215 \r
216                 if (d < bestd)\r
217                 {\r
218                         bestd = d;\r
219                         besti = i;\r
220                 }\r
221         }\r
222 \r
223         if (besti == -1)\r
224         {\r
225                 Sys_Printf ("Click didn't hit a vertex\n");\r
226                 return;\r
227         }\r
228         Sys_Printf ("hit vertex\n");\r
229         g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = g_qeglobals.d_points[besti];\r
230         if (!g_PrefsDlg.m_bVertexSplit)\r
231   {\r
232           SelectVertex (besti);\r
233   }\r
234 }\r
235 \r
236 // TTimo: NOTE: we should not have to put extern funcs like that\r
237 //   those should be defined in qe3.h\r
238 extern void AddPatchMovePoint(vec3_t v, bool bMulti, bool bFull);\r
239 extern int PointInMoveList(float *pf);\r
240 void SelectCurvePointByRay (vec3_t org, vec3_t dir, int buttons)\r
241 {\r
242         int             i, j;\r
243         float   d, bestd = VEC_MAX;\r
244         vec3_t  *pPointBest;\r
245   vec_t epsilon, divergence;\r
246   ray_t ray;\r
247   ray_construct_for_vec3(&ray, org, dir);\r
248 \r
249         // find the point closest to the ray\r
250         pPointBest = NULL;\r
251         if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord)\r
252                 && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view\r
253   {\r
254     divergence = 0;\r
255                 epsilon = SELECT_EPSILON /  g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level\r
256   }\r
257   else\r
258   {\r
259     divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length\r
260     epsilon = 0;\r
261   }\r
262 \r
263 \r
264         g_qeglobals.d_numpoints = 0;\r
265 \r
266         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)\r
267         {\r
268                 if (pb->patchBrush)\r
269                 {\r
270                         patchMesh_t* p = pb->pPatch;\r
271                         \r
272                         for (i = 0 ; i < p->width ; i++ ) \r
273                         {\r
274                                 for ( j = 0 ; j < p->height ; j++ )\r
275                                 {\r
276           d = ray_intersect_point(&ray, p->ctrl[i][j].xyz, epsilon, divergence);\r
277 \r
278                                         if (d >= bestd)\r
279                                                 continue;\r
280                                         \r
281                                         bestd = d;\r
282 \r
283                                         if (PointInMoveList(*pPointBest) != -1 && PointInMoveList(p->ctrl[i][j].xyz) == -1)\r
284                                                 continue; // choose selected points with preference over unselected\r
285 \r
286                                         pPointBest = &p->ctrl[i][j].xyz;\r
287                                         \r
288                                 }\r
289                         }\r
290                 }\r
291         }\r
292 \r
293         if (pPointBest == NULL)\r
294         {\r
295                 if (g_pParentWnd->ActiveXY()->AreaSelectOK())\r
296                 {\r
297                         g_qeglobals.d_select_mode = sel_area;\r
298                         VectorCopy(org, g_qeglobals.d_vAreaTL);\r
299                         VectorCopy(org, g_qeglobals.d_vAreaBR);\r
300                 }\r
301                 return;\r
302         }\r
303         else\r
304                 AddPatchMovePoint(pPointBest[0], buttons & MK_CONTROL, buttons & MK_SHIFT);\r
305 }\r
306 \r
307 // optimization bug:\r
308 // had to use the #define DBG_WNDG to identify\r
309 // the first loop that checks the best edge is broken in release-optimized build\r
310 // unrolled the mid[] loop and forced floating consistency on seems to fix\r
311 #ifdef _WIN32\r
312 #pragma optimize( "p", on )\r
313 #endif\r
314 void SelectEdgeByRay (vec3_t org, vec3_t dir)\r
315 {\r
316         int             i, besti;\r
317         float   d, bestd = VEC_MAX;\r
318         vec3_t  mid;\r
319         pedge_t *e;\r
320   vec_t epsilon, divergence;\r
321   ray_t ray;\r
322   ray_construct_for_vec3(&ray, org, dir);\r
323 \r
324         // find the edge closest to the ray\r
325         besti = -1;\r
326         if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord)\r
327                 && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view\r
328   {\r
329     divergence = 0;\r
330                 epsilon = SELECT_EPSILON /  g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level\r
331   }\r
332   else\r
333   {\r
334     divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length\r
335     epsilon = 0;\r
336   }\r
337 \r
338         for (i=0 ; i<g_qeglobals.d_numedges ; i++)\r
339         {\r
340     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
341     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
342     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
343 \r
344                 d = ray_intersect_point(&ray, mid, epsilon, divergence);\r
345 \r
346 #ifdef DBG_WNDG\r
347     Sys_Printf("d: %f\n", d);\r
348 #endif\r
349                 if (d < bestd)\r
350                 {\r
351 #ifdef DBG_WNDG\r
352       Sys_Printf("bestd = d\n");\r
353 #endif\r
354                         bestd = d;\r
355                         besti = i;\r
356                 }\r
357         }\r
358 \r
359         if (besti == -1)\r
360         {\r
361                 Sys_Printf ("Click didn't hit an edge\n");\r
362                 return;\r
363         }\r
364         Sys_Printf ("Hit edge\n");\r
365 \r
366         // make the two faces that border the edge use the two edge points\r
367         // as primary drag points\r
368         g_qeglobals.d_num_move_points = 0;\r
369         e = &g_qeglobals.d_edges[besti];\r
370 #ifdef DBG_WNDG\r
371   Sys_Printf("besti: %d\n", besti);\r
372   if (e->f1 == NULL)\r
373   {\r
374     Sys_Printf ("e->f1 == NULL e->f2 %p\n", e->f2);\r
375   }\r
376   if (e->f2 == NULL)\r
377   {\r
378     Sys_Printf ("e->f1 %p e->f2 == NULL\n",e->f1);\r
379   }\r
380 #endif\r
381         for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next)\r
382   {\r
383     SelectFaceEdge (b, e->f1, e->p1, e->p2);\r
384           SelectFaceEdge (b, e->f2, e->p2, e->p1);\r
385   }\r
386 }\r