]> git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/textool/ControlPointsManager.cpp
some updates to the Linux build system - obtained a core binary and all required...
[xonotic/netradiant.git] / plugins / textool / ControlPointsManager.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 //-----------------------------------------------------------------------------\r
23 //\r
24 // DESCRIPTION:\r
25 // a class to handle control points in a 2D view\r
26 // TODO: this one can be placed under an interface, and provided to the editor as service\r
27 //\r
28 \r
29 #include "StdAfx.h"\r
30 \r
31 void CControlPointsManagerBFace::Init (int iPts, CtrlPts_t *Pts, C2DView *p2DView, int TexSize[2],\r
32                                        _QERFaceData* pFaceData, _QERQglTable *pQglTable)\r
33 {\r
34   ManagerState = Idle;\r
35   m_NumPoints = iPts;\r
36   m_pPts = Pts;\r
37   // store the initial config\r
38   memcpy( &m_RefPts, Pts, sizeof( CtrlPts_t ) );\r
39   // init TM\r
40   memset( m_TM, 0, sizeof( float[2][3] ) );\r
41   m_TM[0][0] = 1.0f; m_TM[1][1] = 1.0f;\r
42   m_bGotAnchor = false;\r
43   m_TransOffset[0] = 0.0f; m_TransOffset[1] = 0.0f;\r
44   m_TexSize[0] = TexSize[0];\r
45   m_TexSize[1] = TexSize[1];\r
46   m_pFaceData = pFaceData;\r
47 \r
48   CControlPointsManager::Init( p2DView, pQglTable );\r
49 }\r
50 \r
51 bool CControlPointsManagerBFace::OnLButtonDown (int xPos, int yPos)\r
52 {\r
53   if (ManagerState == Idle)\r
54   {\r
55     int i;\r
56 \r
57     // scan the point list to see if we selected something\r
58     for ( i=0; i<m_NumPoints; i++ )\r
59       if ( m_p2DView->DoesSelect( xPos, yPos, m_pPts->data[i] ) )\r
60       {\r
61         m_iDragPoint = i;\r
62         ManagerState = Drag;\r
63         if (m_bGotAnchor && i == m_iAnchorPoint)\r
64         {\r
65           // this means we selected the Anchor, so we'll translate\r
66           m_bGotAnchor = false;\r
67         }\r
68         // perhaps we won't use translation, but we can compute it anyway\r
69         ComputeTransOffset(i);\r
70         if (m_bGotAnchor)\r
71         {\r
72           // we have an Anchor and selected another point\r
73           m_Anchor[0] = m_pPts->data[m_iAnchorPoint][0];\r
74           m_Anchor[1] = m_pPts->data[m_iAnchorPoint][1];\r
75         }\r
76       }\r
77     // send a repaint message\r
78     g_pToolWnd->Redraw ();\r
79     return true;\r
80   }\r
81   return false;\r
82 }\r
83 \r
84 bool CControlPointsManagerBFace::OnMouseMove (int xPos, int yPos)\r
85 {\r
86   if (ManagerState == Drag)\r
87   {\r
88     if (m_bGotAnchor)\r
89     {\r
90       // there's an anchor, we are rotating the shape\r
91       // we need to work in XY space for orthonormality\r
92       float Pt[2];\r
93       vec3_t V1,V2;\r
94       vec3_t cross;\r
95       float c,s;\r
96       // used in XY space\r
97       float XYTM[2][3];\r
98       float XYRefAnchor[2];\r
99       float XYAnchor[2];\r
100       m_p2DView->GridForWindow( Pt, xPos, yPos );\r
101       V2[0] = Pt[0] - m_Anchor[0];\r
102       V2[1] = Pt[1] - m_Anchor[1];\r
103       V2[2] = 0.0f;\r
104       V1[0] = m_RefPts.data[m_iDragPoint][0] - m_RefPts.data[m_iAnchorPoint][0];\r
105       V1[1] = m_RefPts.data[m_iDragPoint][1] - m_RefPts.data[m_iAnchorPoint][1];\r
106       V1[2] = 0.0f;\r
107       // compute transformation from V1 to V2\r
108       // we need to work in XY orthonormal space\r
109       XYSpaceForSTSpace( V1, V1 );\r
110       XYSpaceForSTSpace( V2, V2 );\r
111       VectorNormalize( V2, V2 );\r
112       VectorNormalize( V1, V1 );\r
113       c = DotProduct( V1, V2 );\r
114       CrossProduct( V1, V2, cross );\r
115       s = VectorLength( cross );\r
116       // we compute the transformation matrix in XY space\r
117       // reference position of the Anchor in XY space\r
118       XYSpaceForSTSpace( XYRefAnchor, m_RefPts.data[m_iAnchorPoint] );\r
119       // current position of the Anchor in XY space\r
120       XYSpaceForSTSpace( XYAnchor, m_Anchor );\r
121       // compute transformation matrix\r
122       XYTM[0][0] = c; XYTM[1][1] = c;\r
123       if (cross[2]>0)\r
124         s *= -1.0f;\r
125       XYTM[0][1] = s; XYTM[1][0] = -s;\r
126       XYTM[0][2] = -c*XYRefAnchor[0] - s*XYRefAnchor[1] + XYAnchor[0];\r
127       XYTM[1][2] = s*XYRefAnchor[0] - c*XYRefAnchor[1] + XYAnchor[1];\r
128       // express this transformation matrix in ST space\r
129       m_TM[0][0] = XYTM[0][0];\r
130       m_TM[1][0] = XYTM[1][0] * (float)m_TexSize[0] / (float)m_TexSize[1];\r
131       m_TM[0][1] = XYTM[0][1] * (float)m_TexSize[1] / (float)m_TexSize[0];\r
132       m_TM[1][1] = XYTM[1][1];\r
133       m_TM[0][2] = XYTM[0][2] / (float)m_TexSize[0];\r
134       m_TM[1][2] = XYTM[1][2] / (float)m_TexSize[1];\r
135       // update all points\r
136       UpdateCtrlPts();\r
137     }\r
138     else\r
139     {\r
140       // no Anchor point is defined, we translate all points\r
141       m_p2DView->GridForWindow( m_pPts->data[m_iDragPoint], xPos, yPos );\r
142       m_TM[0][2] = m_pPts->data[m_iDragPoint][0] + m_TransOffset[0];\r
143       m_TM[1][2] = m_pPts->data[m_iDragPoint][1] + m_TransOffset[1];\r
144       // update all points\r
145       UpdateCtrlPts();\r
146     }\r
147     // send a repaint message\r
148     g_pToolWnd->Redraw ();\r
149     return true;\r
150   }\r
151 \r
152   return false;\r
153 }\r
154 \r
155 bool CControlPointsManagerBFace::OnLButtonUp (int x, int y)\r
156 {\r
157   if (ManagerState == Drag)\r
158   {\r
159     // this button is gonna become our Anchor\r
160     m_bGotAnchor = true;\r
161     m_iAnchorPoint = m_iDragPoint;\r
162     // let's get out of Drag mode\r
163     ManagerState = Idle;\r
164     // send a repaint message\r
165     g_pToolWnd->Redraw ();\r
166     return true;\r
167   }\r
168   return false;\r
169 }\r
170 \r
171 void CControlPointsManagerBFace::Render()\r
172 {\r
173   int i;\r
174 \r
175   m_pQglTable->m_pfn_qglColor3f(0, 1, 0);\r
176   m_pQglTable->m_pfn_qglPointSize(6);\r
177   m_pQglTable->m_pfn_qglBegin( GL_POINTS );\r
178   for ( i=0; i<m_NumPoints; i++ )\r
179   {\r
180     if ( ManagerState == Drag && i == m_iDragPoint )\r
181       m_pQglTable->m_pfn_qglColor3f(1, 0, 0);\r
182     else if ( m_bGotAnchor && i == m_iAnchorPoint )\r
183       m_pQglTable->m_pfn_qglColor3f(0, 0, 1);\r
184     m_pQglTable->m_pfn_qglVertex2f( m_pPts->data[i][0], m_pPts->data[i][1] );\r
185     m_pQglTable->m_pfn_qglColor3f(0, 1, 0);\r
186   }\r
187   m_pQglTable->m_pfn_qglEnd();\r
188 }\r
189 \r
190 void CControlPointsManagerBFace::UpdateCtrlPts()\r
191 {\r
192   int i;\r
193 \r
194   // update all points\r
195   for ( i=0; i<m_NumPoints; i++ )\r
196   {\r
197     m_pPts->data[i][0] = m_RefPts.data[i][0]*m_TM[0][0]+m_RefPts.data[i][1]*m_TM[0][1]+m_TM[0][2];\r
198     m_pPts->data[i][1] = m_RefPts.data[i][0]*m_TM[1][0]+m_RefPts.data[i][1]*m_TM[1][1]+m_TM[1][2];\r
199   }\r
200 \r
201   if (g_bPrefsUpdateCameraView)\r
202   {\r
203     Commit();\r
204     // tell Radiant to update\r
205     // NOTE: little speed optimisation, disable window updates, and only update camera view\r
206     g_FuncTable.m_pfnSetScreenUpdate( false );\r
207     g_SelectedFaceTable.m_pfnSetFaceInfo( 0, m_pFaceData );\r
208     g_FuncTable.m_pfnSetScreenUpdate( true );\r
209     g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );\r
210   }\r
211 }\r
212 \r
213 //++timo FIXME: we are using a global for the reference data, use a m_pCancelFaceData instead\r
214 void CControlPointsManagerBFace::Commit( )\r
215 {\r
216   brushprimit_texdef_t aux;\r
217   aux.coords[0][0] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][0] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][0];\r
218   aux.coords[0][1] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][1] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][1];\r
219   aux.coords[0][2] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][2] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][2] + m_TM[0][2];\r
220   aux.coords[1][0] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][0] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][0];\r
221   aux.coords[1][1] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][1] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][1];\r
222   aux.coords[1][2] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][2] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][2] + m_TM[1][2];\r
223   memcpy( &m_pFaceData->brushprimit_texdef, &aux, sizeof(brushprimit_texdef_t) );\r
224 }\r
225 \r
226 void CControlPointsManagerBFace::ComputeTransOffset(int i)\r
227 {\r
228   // compute the translation offset used to counteract rotation\r
229   m_TransOffset[0] = -m_TM[0][0]*m_RefPts.data[i][0] - m_TM[0][1]*m_RefPts.data[i][1];\r
230   m_TransOffset[1] = -m_TM[1][0]*m_RefPts.data[i][0] - m_TM[1][1]*m_RefPts.data[i][1];\r
231 }\r
232 \r
233 void CControlPointsManagerBFace::XYSpaceForSTSpace( float xy[2], const float st[2] )\r
234 {\r
235   xy[0] = st[0] * (float)m_TexSize[0];\r
236   xy[1] = st[1] * (float)m_TexSize[1];\r
237 }\r
238 \r
239 /*\r
240 ======================================================================\r
241 patch manager\r
242 ======================================================================\r
243 */\r
244 \r
245 void CControlPointsManagerPatch::Init( patchMesh_t* pWorkPatch, C2DView *p2DView, _QERQglTable *pQglTable, patchMesh_t* pPatch )\r
246 {\r
247   CControlPointsManager::Init( p2DView, pQglTable );\r
248   m_pPatch = pPatch;\r
249   m_pWorkPatch = pWorkPatch;\r
250 }\r
251 \r
252 bool CControlPointsManagerPatch::OnLButtonDown (int xPos, int yPos)\r
253 {\r
254   if (ManagerState == Idle)\r
255   {\r
256     int i,j;\r
257 \r
258     // scan the point list to see if we selected something\r
259     for ( i=0; i<m_pPatch->width; i++ )\r
260       for ( j=0; j<m_pPatch->height; j++ )\r
261         if ( m_p2DView->DoesSelect( xPos, yPos, m_pWorkPatch->ctrl[i][j].st ) )\r
262         {\r
263           m_iDragPoint[0] = i;\r
264           m_iDragPoint[1] = j;\r
265           ManagerState = Drag;\r
266         }\r
267     // send a repaint message\r
268     g_pToolWnd->Redraw ();\r
269     return true;\r
270   }\r
271   return false;\r
272 }\r
273 \r
274 bool CControlPointsManagerPatch::OnMouseMove (int xPos, int yPos)\r
275 {\r
276   if (ManagerState == Drag)\r
277   {\r
278     m_p2DView->GridForWindow( m_pWorkPatch->ctrl[ m_iDragPoint[0] ][ m_iDragPoint[1] ].st, xPos, yPos );\r
279     if (g_bPrefsUpdateCameraView)\r
280     {\r
281       Commit();\r
282       // ask to rebuild the patch display data\r
283       m_pPatch->bDirty = true;\r
284       // send a repaint to the camera window as well\r
285       g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );\r
286     }\r
287     // send a repaint message\r
288     g_pToolWnd->Redraw ();\r
289     return true;\r
290   }\r
291   return false;\r
292 }\r
293 \r
294 bool CControlPointsManagerPatch::OnLButtonUp (int x, int y)\r
295 {\r
296   if (ManagerState == Drag)\r
297   {\r
298     ManagerState = Idle;\r
299     // send a repaint message\r
300     g_pToolWnd->Redraw ();\r
301   }\r
302   return false;\r
303 }\r
304 \r
305 void CControlPointsManagerPatch::Render()\r
306 {\r
307   int i,j;\r
308 \r
309   m_pQglTable->m_pfn_qglColor3f(0, 1, 0);\r
310   m_pQglTable->m_pfn_qglPointSize(6);\r
311   m_pQglTable->m_pfn_qglBegin( GL_POINTS );\r
312   for ( i=0; i<m_pPatch->width; i++ )\r
313     for ( j=0; j<m_pPatch->height; j++ )\r
314     {\r
315       if ( ManagerState == Drag && i == m_iDragPoint[0] && j == m_iDragPoint[1] )\r
316         m_pQglTable->m_pfn_qglColor3f(1, 0, 0);\r
317       m_pQglTable->m_pfn_qglVertex2f( m_pWorkPatch->ctrl[i][j].st[0], m_pWorkPatch->ctrl[i][j].st[1] );\r
318       m_pQglTable->m_pfn_qglColor3f(0, 1, 0);\r
319     }\r
320   m_pQglTable->m_pfn_qglEnd();\r
321 }\r
322 \r
323 void CControlPointsManagerPatch::Commit()\r
324 {\r
325   int i,j;\r
326   for ( i=0; i<m_pPatch->width; i++ )\r
327     for ( j=0; j<m_pPatch->height; j++ )\r
328     {\r
329       m_pPatch->ctrl[i][j].st[0] = m_pWorkPatch->ctrl[i][j].st[0];\r
330       m_pPatch->ctrl[i][j].st[1] = m_pWorkPatch->ctrl[i][j].st[1];\r
331     }\r
332 }\r