2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\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
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
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
22 //-----------------------------------------------------------------------------
\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
31 void CControlPointsManagerBFace::Init (int iPts, CtrlPts_t *Pts, C2DView *p2DView, int TexSize[2],
\r
32 _QERFaceData* pFaceData, _QERQglTable *pQglTable)
\r
34 ManagerState = Idle;
\r
37 // store the initial config
\r
38 memcpy( &m_RefPts, Pts, sizeof( CtrlPts_t ) );
\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
48 CControlPointsManager::Init( p2DView, pQglTable );
\r
51 bool CControlPointsManagerBFace::OnLButtonDown (int xPos, int yPos)
\r
53 if (ManagerState == Idle)
\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
62 ManagerState = Drag;
\r
63 if (m_bGotAnchor && i == m_iAnchorPoint)
\r
65 // this means we selected the Anchor, so we'll translate
\r
66 m_bGotAnchor = false;
\r
68 // perhaps we won't use translation, but we can compute it anyway
\r
69 ComputeTransOffset(i);
\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
77 // send a repaint message
\r
78 g_pToolWnd->Redraw ();
\r
84 bool CControlPointsManagerBFace::OnMouseMove (int xPos, int yPos)
\r
86 if (ManagerState == Drag)
\r
90 // there's an anchor, we are rotating the shape
\r
91 // we need to work in XY space for orthonormality
\r
98 float XYRefAnchor[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
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
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
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
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
147 // send a repaint message
\r
148 g_pToolWnd->Redraw ();
\r
155 bool CControlPointsManagerBFace::OnLButtonUp (int x, int y)
\r
157 if (ManagerState == Drag)
\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
171 void CControlPointsManagerBFace::Render()
\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
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
187 m_pQglTable->m_pfn_qglEnd();
\r
190 void CControlPointsManagerBFace::UpdateCtrlPts()
\r
194 // update all points
\r
195 for ( i=0; i<m_NumPoints; i++ )
\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
201 if (g_bPrefsUpdateCameraView)
\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
213 //++timo FIXME: we are using a global for the reference data, use a m_pCancelFaceData instead
\r
214 void CControlPointsManagerBFace::Commit( )
\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
226 void CControlPointsManagerBFace::ComputeTransOffset(int i)
\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
233 void CControlPointsManagerBFace::XYSpaceForSTSpace( float xy[2], const float st[2] )
\r
235 xy[0] = st[0] * (float)m_TexSize[0];
\r
236 xy[1] = st[1] * (float)m_TexSize[1];
\r
240 ======================================================================
\r
242 ======================================================================
\r
245 void CControlPointsManagerPatch::Init( patchMesh_t* pWorkPatch, C2DView *p2DView, _QERQglTable *pQglTable, patchMesh_t* pPatch )
\r
247 CControlPointsManager::Init( p2DView, pQglTable );
\r
249 m_pWorkPatch = pWorkPatch;
\r
252 bool CControlPointsManagerPatch::OnLButtonDown (int xPos, int yPos)
\r
254 if (ManagerState == Idle)
\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
263 m_iDragPoint[0] = i;
\r
264 m_iDragPoint[1] = j;
\r
265 ManagerState = Drag;
\r
267 // send a repaint message
\r
268 g_pToolWnd->Redraw ();
\r
274 bool CControlPointsManagerPatch::OnMouseMove (int xPos, int yPos)
\r
276 if (ManagerState == Drag)
\r
278 m_p2DView->GridForWindow( m_pWorkPatch->ctrl[ m_iDragPoint[0] ][ m_iDragPoint[1] ].st, xPos, yPos );
\r
279 if (g_bPrefsUpdateCameraView)
\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
287 // send a repaint message
\r
288 g_pToolWnd->Redraw ();
\r
294 bool CControlPointsManagerPatch::OnLButtonUp (int x, int y)
\r
296 if (ManagerState == Drag)
\r
298 ManagerState = Idle;
\r
299 // send a repaint message
\r
300 g_pToolWnd->Redraw ();
\r
305 void CControlPointsManagerPatch::Render()
\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
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
320 m_pQglTable->m_pfn_qglEnd();
\r
323 void CControlPointsManagerPatch::Commit()
\r
326 for ( i=0; i<m_pPatch->width; i++ )
\r
327 for ( j=0; j<m_pPatch->height; j++ )
\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