2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 //-----------------------------------------------------------------------------
25 // a class to handle control points in a 2D view
26 // TODO: this one can be placed under an interface, and provided to the editor as service
31 void CControlPointsManagerBFace::Init( int iPts, CtrlPts_t *Pts, C2DView *p2DView, int TexSize[2],
32 _QERFaceData* pFaceData, OpenGLBinding *pQglTable ){
36 // store the initial config
37 memcpy( &m_RefPts, Pts, sizeof( CtrlPts_t ) );
39 memset( m_TM, 0, sizeof( float[2][3] ) );
40 m_TM[0][0] = 1.0f; m_TM[1][1] = 1.0f;
42 m_TransOffset[0] = 0.0f; m_TransOffset[1] = 0.0f;
43 m_TexSize[0] = TexSize[0];
44 m_TexSize[1] = TexSize[1];
45 m_pFaceData = pFaceData;
47 CControlPointsManager::Init( p2DView, pQglTable );
50 bool CControlPointsManagerBFace::OnLButtonDown( int xPos, int yPos ){
51 if ( ManagerState == Idle ) {
54 // scan the point list to see if we selected something
55 for ( i = 0; i < m_NumPoints; i++ )
56 if ( m_p2DView->DoesSelect( xPos, yPos, m_pPts->data[i] ) ) {
59 if ( m_bGotAnchor && i == m_iAnchorPoint ) {
60 // this means we selected the Anchor, so we'll translate
63 // perhaps we won't use translation, but we can compute it anyway
64 ComputeTransOffset( i );
66 // we have an Anchor and selected another point
67 m_Anchor[0] = m_pPts->data[m_iAnchorPoint][0];
68 m_Anchor[1] = m_pPts->data[m_iAnchorPoint][1];
71 // send a repaint message
78 bool CControlPointsManagerBFace::OnMouseMove( int xPos, int yPos ){
79 if ( ManagerState == Drag ) {
81 // there's an anchor, we are rotating the shape
82 // we need to work in XY space for orthonormality
91 m_p2DView->GridForWindow( Pt, xPos, yPos );
92 V2[0] = Pt[0] - m_Anchor[0];
93 V2[1] = Pt[1] - m_Anchor[1];
95 V1[0] = m_RefPts.data[m_iDragPoint][0] - m_RefPts.data[m_iAnchorPoint][0];
96 V1[1] = m_RefPts.data[m_iDragPoint][1] - m_RefPts.data[m_iAnchorPoint][1];
98 // compute transformation from V1 to V2
99 // we need to work in XY orthonormal space
100 XYSpaceForSTSpace( V1, V1 );
101 XYSpaceForSTSpace( V2, V2 );
102 VectorNormalize( V2, V2 );
103 VectorNormalize( V1, V1 );
104 c = DotProduct( V1, V2 );
105 CrossProduct( V1, V2, cross );
106 s = VectorLength( cross );
107 // we compute the transformation matrix in XY space
108 // reference position of the Anchor in XY space
109 XYSpaceForSTSpace( XYRefAnchor, m_RefPts.data[m_iAnchorPoint] );
110 // current position of the Anchor in XY space
111 XYSpaceForSTSpace( XYAnchor, m_Anchor );
112 // compute transformation matrix
113 XYTM[0][0] = c; XYTM[1][1] = c;
114 if ( cross[2] > 0 ) {
117 XYTM[0][1] = s; XYTM[1][0] = -s;
118 XYTM[0][2] = -c * XYRefAnchor[0] - s * XYRefAnchor[1] + XYAnchor[0];
119 XYTM[1][2] = s * XYRefAnchor[0] - c * XYRefAnchor[1] + XYAnchor[1];
120 // express this transformation matrix in ST space
121 m_TM[0][0] = XYTM[0][0];
122 m_TM[1][0] = XYTM[1][0] * (float)m_TexSize[0] / (float)m_TexSize[1];
123 m_TM[0][1] = XYTM[0][1] * (float)m_TexSize[1] / (float)m_TexSize[0];
124 m_TM[1][1] = XYTM[1][1];
125 m_TM[0][2] = XYTM[0][2] / (float)m_TexSize[0];
126 m_TM[1][2] = XYTM[1][2] / (float)m_TexSize[1];
132 // no Anchor point is defined, we translate all points
133 m_p2DView->GridForWindow( m_pPts->data[m_iDragPoint], xPos, yPos );
134 m_TM[0][2] = m_pPts->data[m_iDragPoint][0] + m_TransOffset[0];
135 m_TM[1][2] = m_pPts->data[m_iDragPoint][1] + m_TransOffset[1];
139 // send a repaint message
140 g_pToolWnd->Redraw();
147 bool CControlPointsManagerBFace::OnLButtonUp( int x, int y ){
148 if ( ManagerState == Drag ) {
149 // this button is gonna become our Anchor
151 m_iAnchorPoint = m_iDragPoint;
152 // let's get out of Drag mode
154 // send a repaint message
155 g_pToolWnd->Redraw();
161 void CControlPointsManagerBFace::render(){
164 m_pQglTable->m_pfn_qglColor3f( 0, 1, 0 );
165 m_pQglTable->m_pfn_qglPointSize( 6 );
166 m_pQglTable->m_pfn_qglBegin( GL_POINTS );
167 for ( i = 0; i < m_NumPoints; i++ )
169 if ( ManagerState == Drag && i == m_iDragPoint ) {
170 m_pQglTable->m_pfn_qglColor3f( 1, 0, 0 );
172 else if ( m_bGotAnchor && i == m_iAnchorPoint ) {
173 m_pQglTable->m_pfn_qglColor3f( 0, 0, 1 );
175 m_pQglTable->m_pfn_qglVertex2f( m_pPts->data[i][0], m_pPts->data[i][1] );
176 m_pQglTable->m_pfn_qglColor3f( 0, 1, 0 );
178 m_pQglTable->m_pfn_qglEnd();
181 void CControlPointsManagerBFace::UpdateCtrlPts(){
185 for ( i = 0; i < m_NumPoints; i++ )
187 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];
188 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];
191 if ( g_bPrefsUpdateCameraView ) {
193 // tell Radiant to update
194 // NOTE: little speed optimisation, disable window updates, and only update camera view
195 g_FuncTable.m_pfnSetScreenUpdate( false );
196 g_SelectedFaceTable.m_pfnSetFaceInfo( 0, m_pFaceData );
197 g_FuncTable.m_pfnSetScreenUpdate( true );
198 g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );
202 //++timo FIXME: we are using a global for the reference data, use a m_pCancelFaceData instead
203 void CControlPointsManagerBFace::Commit(){
204 brushprimit_texdef_t aux;
205 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];
206 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];
207 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];
208 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];
209 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];
210 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];
211 memcpy( &m_pFaceData->brushprimit_texdef, &aux, sizeof( brushprimit_texdef_t ) );
214 void CControlPointsManagerBFace::ComputeTransOffset( int i ){
215 // compute the translation offset used to counteract rotation
216 m_TransOffset[0] = -m_TM[0][0] * m_RefPts.data[i][0] - m_TM[0][1] * m_RefPts.data[i][1];
217 m_TransOffset[1] = -m_TM[1][0] * m_RefPts.data[i][0] - m_TM[1][1] * m_RefPts.data[i][1];
220 void CControlPointsManagerBFace::XYSpaceForSTSpace( float xy[2], const float st[2] ){
221 xy[0] = st[0] * (float)m_TexSize[0];
222 xy[1] = st[1] * (float)m_TexSize[1];
226 ======================================================================
228 ======================================================================
231 void CControlPointsManagerPatch::Init( patchMesh_t* pWorkPatch, C2DView *p2DView, OpenGLBinding *pQglTable, patchMesh_t* pPatch ){
232 CControlPointsManager::Init( p2DView, pQglTable );
234 m_pWorkPatch = pWorkPatch;
237 bool CControlPointsManagerPatch::OnLButtonDown( int xPos, int yPos ){
238 if ( ManagerState == Idle ) {
241 // scan the point list to see if we selected something
242 for ( i = 0; i < m_pPatch->width; i++ )
243 for ( j = 0; j < m_pPatch->height; j++ )
244 if ( m_p2DView->DoesSelect( xPos, yPos, m_pWorkPatch->ctrl[i][j].st ) ) {
249 // send a repaint message
250 g_pToolWnd->Redraw();
256 bool CControlPointsManagerPatch::OnMouseMove( int xPos, int yPos ){
257 if ( ManagerState == Drag ) {
258 m_p2DView->GridForWindow( m_pWorkPatch->ctrl[ m_iDragPoint[0] ][ m_iDragPoint[1] ].st, xPos, yPos );
259 if ( g_bPrefsUpdateCameraView ) {
261 // ask to rebuild the patch display data
262 m_pPatch->bDirty = true;
263 // send a repaint to the camera window as well
264 g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );
266 // send a repaint message
267 g_pToolWnd->Redraw();
273 bool CControlPointsManagerPatch::OnLButtonUp( int x, int y ){
274 if ( ManagerState == Drag ) {
276 // send a repaint message
277 g_pToolWnd->Redraw();
282 void CControlPointsManagerPatch::render(){
285 m_pQglTable->m_pfn_qglColor3f( 0, 1, 0 );
286 m_pQglTable->m_pfn_qglPointSize( 6 );
287 m_pQglTable->m_pfn_qglBegin( GL_POINTS );
288 for ( i = 0; i < m_pPatch->width; i++ )
289 for ( j = 0; j < m_pPatch->height; j++ )
291 if ( ManagerState == Drag && i == m_iDragPoint[0] && j == m_iDragPoint[1] ) {
292 m_pQglTable->m_pfn_qglColor3f( 1, 0, 0 );
294 m_pQglTable->m_pfn_qglVertex2f( m_pWorkPatch->ctrl[i][j].st[0], m_pWorkPatch->ctrl[i][j].st[1] );
295 m_pQglTable->m_pfn_qglColor3f( 0, 1, 0 );
297 m_pQglTable->m_pfn_qglEnd();
300 void CControlPointsManagerPatch::Commit(){
302 for ( i = 0; i < m_pPatch->width; i++ )
303 for ( j = 0; j < m_pPatch->height; j++ )
305 m_pPatch->ctrl[i][j].st[0] = m_pWorkPatch->ctrl[i][j].st[0];
306 m_pPatch->ctrl[i][j].st[1] = m_pWorkPatch->ctrl[i][j].st[1];