]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - plugins/textool/ControlPointsManager.cpp
more eol-style
[xonotic/netradiant.git] / plugins / textool / ControlPointsManager.cpp
index e91a694002e31cf23bd2d711563028736169516b..814ddf9de72c88d14b997246d24601ebe9c01e3b 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
-//-----------------------------------------------------------------------------\r
-//\r
-// DESCRIPTION:\r
-// a class to handle control points in a 2D view\r
-// TODO: this one can be placed under an interface, and provided to the editor as service\r
-//\r
-\r
-#include "StdAfx.h"\r
-\r
-void CControlPointsManagerBFace::Init (int iPts, CtrlPts_t *Pts, C2DView *p2DView, int TexSize[2],\r
-                                      _QERFaceData* pFaceData, _QERQglTable *pQglTable)\r
-{\r
-  ManagerState = Idle;\r
-  m_NumPoints = iPts;\r
-  m_pPts = Pts;\r
-  // store the initial config\r
-  memcpy( &m_RefPts, Pts, sizeof( CtrlPts_t ) );\r
-  // init TM\r
-  memset( m_TM, 0, sizeof( float[2][3] ) );\r
-  m_TM[0][0] = 1.0f; m_TM[1][1] = 1.0f;\r
-  m_bGotAnchor = false;\r
-  m_TransOffset[0] = 0.0f; m_TransOffset[1] = 0.0f;\r
-  m_TexSize[0] = TexSize[0];\r
-  m_TexSize[1] = TexSize[1];\r
-  m_pFaceData = pFaceData;\r
-\r
-  CControlPointsManager::Init( p2DView, pQglTable );\r
-}\r
-\r
-bool CControlPointsManagerBFace::OnLButtonDown (int xPos, int yPos)\r
-{\r
-  if (ManagerState == Idle)\r
-  {\r
-    int i;\r
-\r
-    // scan the point list to see if we selected something\r
-    for ( i=0; i<m_NumPoints; i++ )\r
-      if ( m_p2DView->DoesSelect( xPos, yPos, m_pPts->data[i] ) )\r
-      {\r
-       m_iDragPoint = i;\r
-       ManagerState = Drag;\r
-       if (m_bGotAnchor && i == m_iAnchorPoint)\r
-       {\r
-         // this means we selected the Anchor, so we'll translate\r
-         m_bGotAnchor = false;\r
-       }\r
-       // perhaps we won't use translation, but we can compute it anyway\r
-       ComputeTransOffset(i);\r
-       if (m_bGotAnchor)\r
-       {\r
-         // we have an Anchor and selected another point\r
-         m_Anchor[0] = m_pPts->data[m_iAnchorPoint][0];\r
-         m_Anchor[1] = m_pPts->data[m_iAnchorPoint][1];\r
-       }\r
-      }\r
-    // send a repaint message\r
-    g_pToolWnd->Redraw ();\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-bool CControlPointsManagerBFace::OnMouseMove (int xPos, int yPos)\r
-{\r
-  if (ManagerState == Drag)\r
-  {\r
-    if (m_bGotAnchor)\r
-    {\r
-      // there's an anchor, we are rotating the shape\r
-      // we need to work in XY space for orthonormality\r
-      float Pt[2];\r
-      vec3_t V1,V2;\r
-      vec3_t cross;\r
-      float c,s;\r
-      // used in XY space\r
-      float XYTM[2][3];\r
-      float XYRefAnchor[2];\r
-      float XYAnchor[2];\r
-      m_p2DView->GridForWindow( Pt, xPos, yPos );\r
-      V2[0] = Pt[0] - m_Anchor[0];\r
-      V2[1] = Pt[1] - m_Anchor[1];\r
-      V2[2] = 0.0f;\r
-      V1[0] = m_RefPts.data[m_iDragPoint][0] - m_RefPts.data[m_iAnchorPoint][0];\r
-      V1[1] = m_RefPts.data[m_iDragPoint][1] - m_RefPts.data[m_iAnchorPoint][1];\r
-      V1[2] = 0.0f;\r
-      // compute transformation from V1 to V2\r
-      // we need to work in XY orthonormal space\r
-      XYSpaceForSTSpace( V1, V1 );\r
-      XYSpaceForSTSpace( V2, V2 );\r
-      VectorNormalize( V2, V2 );\r
-      VectorNormalize( V1, V1 );\r
-      c = DotProduct( V1, V2 );\r
-      CrossProduct( V1, V2, cross );\r
-      s = VectorLength( cross );\r
-      // we compute the transformation matrix in XY space\r
-      // reference position of the Anchor in XY space\r
-      XYSpaceForSTSpace( XYRefAnchor, m_RefPts.data[m_iAnchorPoint] );\r
-      // current position of the Anchor in XY space\r
-      XYSpaceForSTSpace( XYAnchor, m_Anchor );\r
-      // compute transformation matrix\r
-      XYTM[0][0] = c; XYTM[1][1] = c;\r
-      if (cross[2]>0)\r
-       s *= -1.0f;\r
-      XYTM[0][1] = s; XYTM[1][0] = -s;\r
-      XYTM[0][2] = -c*XYRefAnchor[0] - s*XYRefAnchor[1] + XYAnchor[0];\r
-      XYTM[1][2] = s*XYRefAnchor[0] - c*XYRefAnchor[1] + XYAnchor[1];\r
-      // express this transformation matrix in ST space\r
-      m_TM[0][0] = XYTM[0][0];\r
-      m_TM[1][0] = XYTM[1][0] * (float)m_TexSize[0] / (float)m_TexSize[1];\r
-      m_TM[0][1] = XYTM[0][1] * (float)m_TexSize[1] / (float)m_TexSize[0];\r
-      m_TM[1][1] = XYTM[1][1];\r
-      m_TM[0][2] = XYTM[0][2] / (float)m_TexSize[0];\r
-      m_TM[1][2] = XYTM[1][2] / (float)m_TexSize[1];\r
-      // update all points\r
-      UpdateCtrlPts();\r
-    }\r
-    else\r
-    {\r
-      // no Anchor point is defined, we translate all points\r
-      m_p2DView->GridForWindow( m_pPts->data[m_iDragPoint], xPos, yPos );\r
-      m_TM[0][2] = m_pPts->data[m_iDragPoint][0] + m_TransOffset[0];\r
-      m_TM[1][2] = m_pPts->data[m_iDragPoint][1] + m_TransOffset[1];\r
-      // update all points\r
-      UpdateCtrlPts();\r
-    }\r
-    // send a repaint message\r
-    g_pToolWnd->Redraw ();\r
-    return true;\r
-  }\r
-\r
-  return false;\r
-}\r
-\r
-bool CControlPointsManagerBFace::OnLButtonUp (int x, int y)\r
-{\r
-  if (ManagerState == Drag)\r
-  {\r
-    // this button is gonna become our Anchor\r
-    m_bGotAnchor = true;\r
-    m_iAnchorPoint = m_iDragPoint;\r
-    // let's get out of Drag mode\r
-    ManagerState = Idle;\r
-    // send a repaint message\r
-    g_pToolWnd->Redraw ();\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-void CControlPointsManagerBFace::Render()\r
-{\r
-  int i;\r
-\r
-  m_pQglTable->m_pfn_qglColor3f(0, 1, 0);\r
-  m_pQglTable->m_pfn_qglPointSize(6);\r
-  m_pQglTable->m_pfn_qglBegin( GL_POINTS );\r
-  for ( i=0; i<m_NumPoints; i++ )\r
-  {\r
-    if ( ManagerState == Drag && i == m_iDragPoint )\r
-      m_pQglTable->m_pfn_qglColor3f(1, 0, 0);\r
-    else if ( m_bGotAnchor && i == m_iAnchorPoint )\r
-      m_pQglTable->m_pfn_qglColor3f(0, 0, 1);\r
-    m_pQglTable->m_pfn_qglVertex2f( m_pPts->data[i][0], m_pPts->data[i][1] );\r
-    m_pQglTable->m_pfn_qglColor3f(0, 1, 0);\r
-  }\r
-  m_pQglTable->m_pfn_qglEnd();\r
-}\r
-\r
-void CControlPointsManagerBFace::UpdateCtrlPts()\r
-{\r
-  int i;\r
-\r
-  // update all points\r
-  for ( i=0; i<m_NumPoints; i++ )\r
-  {\r
-    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
-    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
-  }\r
-\r
-  if (g_bPrefsUpdateCameraView)\r
-  {\r
-    Commit();\r
-    // tell Radiant to update\r
-    // NOTE: little speed optimisation, disable window updates, and only update camera view\r
-    g_FuncTable.m_pfnSetScreenUpdate( false );\r
-    g_SelectedFaceTable.m_pfnSetFaceInfo( 0, m_pFaceData );\r
-    g_FuncTable.m_pfnSetScreenUpdate( true );\r
-    g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );\r
-  }\r
-}\r
-\r
-//++timo FIXME: we are using a global for the reference data, use a m_pCancelFaceData instead\r
-void CControlPointsManagerBFace::Commit( )\r
-{\r
-  brushprimit_texdef_t aux;\r
-  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
-  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
-  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
-  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
-  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
-  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
-  memcpy( &m_pFaceData->brushprimit_texdef, &aux, sizeof(brushprimit_texdef_t) );\r
-}\r
-\r
-void CControlPointsManagerBFace::ComputeTransOffset(int i)\r
-{\r
-  // compute the translation offset used to counteract rotation\r
-  m_TransOffset[0] = -m_TM[0][0]*m_RefPts.data[i][0] - m_TM[0][1]*m_RefPts.data[i][1];\r
-  m_TransOffset[1] = -m_TM[1][0]*m_RefPts.data[i][0] - m_TM[1][1]*m_RefPts.data[i][1];\r
-}\r
-\r
-void CControlPointsManagerBFace::XYSpaceForSTSpace( float xy[2], const float st[2] )\r
-{\r
-  xy[0] = st[0] * (float)m_TexSize[0];\r
-  xy[1] = st[1] * (float)m_TexSize[1];\r
-}\r
-\r
-/*\r
-======================================================================\r
-patch manager\r
-======================================================================\r
-*/\r
-\r
-void CControlPointsManagerPatch::Init( patchMesh_t* pWorkPatch, C2DView *p2DView, _QERQglTable *pQglTable, patchMesh_t* pPatch )\r
-{\r
-  CControlPointsManager::Init( p2DView, pQglTable );\r
-  m_pPatch = pPatch;\r
-  m_pWorkPatch = pWorkPatch;\r
-}\r
-\r
-bool CControlPointsManagerPatch::OnLButtonDown (int xPos, int yPos)\r
-{\r
-  if (ManagerState == Idle)\r
-  {\r
-    int i,j;\r
-\r
-    // scan the point list to see if we selected something\r
-    for ( i=0; i<m_pPatch->width; i++ )\r
-      for ( j=0; j<m_pPatch->height; j++ )\r
-       if ( m_p2DView->DoesSelect( xPos, yPos, m_pWorkPatch->ctrl[i][j].st ) )\r
-       {\r
-         m_iDragPoint[0] = i;\r
-         m_iDragPoint[1] = j;\r
-         ManagerState = Drag;\r
-       }\r
-    // send a repaint message\r
-    g_pToolWnd->Redraw ();\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-bool CControlPointsManagerPatch::OnMouseMove (int xPos, int yPos)\r
-{\r
-  if (ManagerState == Drag)\r
-  {\r
-    m_p2DView->GridForWindow( m_pWorkPatch->ctrl[ m_iDragPoint[0] ][ m_iDragPoint[1] ].st, xPos, yPos );\r
-    if (g_bPrefsUpdateCameraView)\r
-    {\r
-      Commit();\r
-      // ask to rebuild the patch display data\r
-      m_pPatch->bDirty = true;\r
-      // send a repaint to the camera window as well\r
-      g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );\r
-    }\r
-    // send a repaint message\r
-    g_pToolWnd->Redraw ();\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-bool CControlPointsManagerPatch::OnLButtonUp (int x, int y)\r
-{\r
-  if (ManagerState == Drag)\r
-  {\r
-    ManagerState = Idle;\r
-    // send a repaint message\r
-    g_pToolWnd->Redraw ();\r
-  }\r
-  return false;\r
-}\r
-\r
-void CControlPointsManagerPatch::Render()\r
-{\r
-  int i,j;\r
-\r
-  m_pQglTable->m_pfn_qglColor3f(0, 1, 0);\r
-  m_pQglTable->m_pfn_qglPointSize(6);\r
-  m_pQglTable->m_pfn_qglBegin( GL_POINTS );\r
-  for ( i=0; i<m_pPatch->width; i++ )\r
-    for ( j=0; j<m_pPatch->height; j++ )\r
-    {\r
-      if ( ManagerState == Drag && i == m_iDragPoint[0] && j == m_iDragPoint[1] )\r
-       m_pQglTable->m_pfn_qglColor3f(1, 0, 0);\r
-      m_pQglTable->m_pfn_qglVertex2f( m_pWorkPatch->ctrl[i][j].st[0], m_pWorkPatch->ctrl[i][j].st[1] );\r
-      m_pQglTable->m_pfn_qglColor3f(0, 1, 0);\r
-    }\r
-  m_pQglTable->m_pfn_qglEnd();\r
-}\r
-\r
-void CControlPointsManagerPatch::Commit()\r
-{\r
-  int i,j;\r
-  for ( i=0; i<m_pPatch->width; i++ )\r
-    for ( j=0; j<m_pPatch->height; j++ )\r
-    {\r
-      m_pPatch->ctrl[i][j].st[0] = m_pWorkPatch->ctrl[i][j].st[0];\r
-      m_pPatch->ctrl[i][j].st[1] = m_pWorkPatch->ctrl[i][j].st[1];\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
+*/
+
+//-----------------------------------------------------------------------------
+//
+// DESCRIPTION:
+// a class to handle control points in a 2D view
+// TODO: this one can be placed under an interface, and provided to the editor as service
+//
+
+#include "StdAfx.h"
+
+void CControlPointsManagerBFace::Init (int iPts, CtrlPts_t *Pts, C2DView *p2DView, int TexSize[2],
+                                      _QERFaceData* pFaceData, _QERQglTable *pQglTable)
+{
+  ManagerState = Idle;
+  m_NumPoints = iPts;
+  m_pPts = Pts;
+  // store the initial config
+  memcpy( &m_RefPts, Pts, sizeof( CtrlPts_t ) );
+  // init TM
+  memset( m_TM, 0, sizeof( float[2][3] ) );
+  m_TM[0][0] = 1.0f; m_TM[1][1] = 1.0f;
+  m_bGotAnchor = false;
+  m_TransOffset[0] = 0.0f; m_TransOffset[1] = 0.0f;
+  m_TexSize[0] = TexSize[0];
+  m_TexSize[1] = TexSize[1];
+  m_pFaceData = pFaceData;
+
+  CControlPointsManager::Init( p2DView, pQglTable );
+}
+
+bool CControlPointsManagerBFace::OnLButtonDown (int xPos, int yPos)
+{
+  if (ManagerState == Idle)
+  {
+    int i;
+
+    // scan the point list to see if we selected something
+    for ( i=0; i<m_NumPoints; i++ )
+      if ( m_p2DView->DoesSelect( xPos, yPos, m_pPts->data[i] ) )
+      {
+       m_iDragPoint = i;
+       ManagerState = Drag;
+       if (m_bGotAnchor && i == m_iAnchorPoint)
+       {
+         // this means we selected the Anchor, so we'll translate
+         m_bGotAnchor = false;
+       }
+       // perhaps we won't use translation, but we can compute it anyway
+       ComputeTransOffset(i);
+       if (m_bGotAnchor)
+       {
+         // we have an Anchor and selected another point
+         m_Anchor[0] = m_pPts->data[m_iAnchorPoint][0];
+         m_Anchor[1] = m_pPts->data[m_iAnchorPoint][1];
+       }
+      }
+    // send a repaint message
+    g_pToolWnd->Redraw ();
+    return true;
+  }
+  return false;
+}
+
+bool CControlPointsManagerBFace::OnMouseMove (int xPos, int yPos)
+{
+  if (ManagerState == Drag)
+  {
+    if (m_bGotAnchor)
+    {
+      // there's an anchor, we are rotating the shape
+      // we need to work in XY space for orthonormality
+      float Pt[2];
+      vec3_t V1,V2;
+      vec3_t cross;
+      float c,s;
+      // used in XY space
+      float XYTM[2][3];
+      float XYRefAnchor[2];
+      float XYAnchor[2];
+      m_p2DView->GridForWindow( Pt, xPos, yPos );
+      V2[0] = Pt[0] - m_Anchor[0];
+      V2[1] = Pt[1] - m_Anchor[1];
+      V2[2] = 0.0f;
+      V1[0] = m_RefPts.data[m_iDragPoint][0] - m_RefPts.data[m_iAnchorPoint][0];
+      V1[1] = m_RefPts.data[m_iDragPoint][1] - m_RefPts.data[m_iAnchorPoint][1];
+      V1[2] = 0.0f;
+      // compute transformation from V1 to V2
+      // we need to work in XY orthonormal space
+      XYSpaceForSTSpace( V1, V1 );
+      XYSpaceForSTSpace( V2, V2 );
+      VectorNormalize( V2, V2 );
+      VectorNormalize( V1, V1 );
+      c = DotProduct( V1, V2 );
+      CrossProduct( V1, V2, cross );
+      s = VectorLength( cross );
+      // we compute the transformation matrix in XY space
+      // reference position of the Anchor in XY space
+      XYSpaceForSTSpace( XYRefAnchor, m_RefPts.data[m_iAnchorPoint] );
+      // current position of the Anchor in XY space
+      XYSpaceForSTSpace( XYAnchor, m_Anchor );
+      // compute transformation matrix
+      XYTM[0][0] = c; XYTM[1][1] = c;
+      if (cross[2]>0)
+       s *= -1.0f;
+      XYTM[0][1] = s; XYTM[1][0] = -s;
+      XYTM[0][2] = -c*XYRefAnchor[0] - s*XYRefAnchor[1] + XYAnchor[0];
+      XYTM[1][2] = s*XYRefAnchor[0] - c*XYRefAnchor[1] + XYAnchor[1];
+      // express this transformation matrix in ST space
+      m_TM[0][0] = XYTM[0][0];
+      m_TM[1][0] = XYTM[1][0] * (float)m_TexSize[0] / (float)m_TexSize[1];
+      m_TM[0][1] = XYTM[0][1] * (float)m_TexSize[1] / (float)m_TexSize[0];
+      m_TM[1][1] = XYTM[1][1];
+      m_TM[0][2] = XYTM[0][2] / (float)m_TexSize[0];
+      m_TM[1][2] = XYTM[1][2] / (float)m_TexSize[1];
+      // update all points
+      UpdateCtrlPts();
+    }
+    else
+    {
+      // no Anchor point is defined, we translate all points
+      m_p2DView->GridForWindow( m_pPts->data[m_iDragPoint], xPos, yPos );
+      m_TM[0][2] = m_pPts->data[m_iDragPoint][0] + m_TransOffset[0];
+      m_TM[1][2] = m_pPts->data[m_iDragPoint][1] + m_TransOffset[1];
+      // update all points
+      UpdateCtrlPts();
+    }
+    // send a repaint message
+    g_pToolWnd->Redraw ();
+    return true;
+  }
+
+  return false;
+}
+
+bool CControlPointsManagerBFace::OnLButtonUp (int x, int y)
+{
+  if (ManagerState == Drag)
+  {
+    // this button is gonna become our Anchor
+    m_bGotAnchor = true;
+    m_iAnchorPoint = m_iDragPoint;
+    // let's get out of Drag mode
+    ManagerState = Idle;
+    // send a repaint message
+    g_pToolWnd->Redraw ();
+    return true;
+  }
+  return false;
+}
+
+void CControlPointsManagerBFace::Render()
+{
+  int i;
+
+  m_pQglTable->m_pfn_qglColor3f(0, 1, 0);
+  m_pQglTable->m_pfn_qglPointSize(6);
+  m_pQglTable->m_pfn_qglBegin( GL_POINTS );
+  for ( i=0; i<m_NumPoints; i++ )
+  {
+    if ( ManagerState == Drag && i == m_iDragPoint )
+      m_pQglTable->m_pfn_qglColor3f(1, 0, 0);
+    else if ( m_bGotAnchor && i == m_iAnchorPoint )
+      m_pQglTable->m_pfn_qglColor3f(0, 0, 1);
+    m_pQglTable->m_pfn_qglVertex2f( m_pPts->data[i][0], m_pPts->data[i][1] );
+    m_pQglTable->m_pfn_qglColor3f(0, 1, 0);
+  }
+  m_pQglTable->m_pfn_qglEnd();
+}
+
+void CControlPointsManagerBFace::UpdateCtrlPts()
+{
+  int i;
+
+  // update all points
+  for ( i=0; i<m_NumPoints; i++ )
+  {
+    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];
+    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];
+  }
+
+  if (g_bPrefsUpdateCameraView)
+  {
+    Commit();
+    // tell Radiant to update
+    // NOTE: little speed optimisation, disable window updates, and only update camera view
+    g_FuncTable.m_pfnSetScreenUpdate( false );
+    g_SelectedFaceTable.m_pfnSetFaceInfo( 0, m_pFaceData );
+    g_FuncTable.m_pfnSetScreenUpdate( true );
+    g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );
+  }
+}
+
+//++timo FIXME: we are using a global for the reference data, use a m_pCancelFaceData instead
+void CControlPointsManagerBFace::Commit( )
+{
+  brushprimit_texdef_t aux;
+  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];
+  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];
+  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];
+  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];
+  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];
+  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];
+  memcpy( &m_pFaceData->brushprimit_texdef, &aux, sizeof(brushprimit_texdef_t) );
+}
+
+void CControlPointsManagerBFace::ComputeTransOffset(int i)
+{
+  // compute the translation offset used to counteract rotation
+  m_TransOffset[0] = -m_TM[0][0]*m_RefPts.data[i][0] - m_TM[0][1]*m_RefPts.data[i][1];
+  m_TransOffset[1] = -m_TM[1][0]*m_RefPts.data[i][0] - m_TM[1][1]*m_RefPts.data[i][1];
+}
+
+void CControlPointsManagerBFace::XYSpaceForSTSpace( float xy[2], const float st[2] )
+{
+  xy[0] = st[0] * (float)m_TexSize[0];
+  xy[1] = st[1] * (float)m_TexSize[1];
+}
+
+/*
+======================================================================
+patch manager
+======================================================================
+*/
+
+void CControlPointsManagerPatch::Init( patchMesh_t* pWorkPatch, C2DView *p2DView, _QERQglTable *pQglTable, patchMesh_t* pPatch )
+{
+  CControlPointsManager::Init( p2DView, pQglTable );
+  m_pPatch = pPatch;
+  m_pWorkPatch = pWorkPatch;
+}
+
+bool CControlPointsManagerPatch::OnLButtonDown (int xPos, int yPos)
+{
+  if (ManagerState == Idle)
+  {
+    int i,j;
+
+    // scan the point list to see if we selected something
+    for ( i=0; i<m_pPatch->width; i++ )
+      for ( j=0; j<m_pPatch->height; j++ )
+       if ( m_p2DView->DoesSelect( xPos, yPos, m_pWorkPatch->ctrl[i][j].st ) )
+       {
+         m_iDragPoint[0] = i;
+         m_iDragPoint[1] = j;
+         ManagerState = Drag;
+       }
+    // send a repaint message
+    g_pToolWnd->Redraw ();
+    return true;
+  }
+  return false;
+}
+
+bool CControlPointsManagerPatch::OnMouseMove (int xPos, int yPos)
+{
+  if (ManagerState == Drag)
+  {
+    m_p2DView->GridForWindow( m_pWorkPatch->ctrl[ m_iDragPoint[0] ][ m_iDragPoint[1] ].st, xPos, yPos );
+    if (g_bPrefsUpdateCameraView)
+    {
+      Commit();
+      // ask to rebuild the patch display data
+      m_pPatch->bDirty = true;
+      // send a repaint to the camera window as well
+      g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );
+    }
+    // send a repaint message
+    g_pToolWnd->Redraw ();
+    return true;
+  }
+  return false;
+}
+
+bool CControlPointsManagerPatch::OnLButtonUp (int x, int y)
+{
+  if (ManagerState == Drag)
+  {
+    ManagerState = Idle;
+    // send a repaint message
+    g_pToolWnd->Redraw ();
+  }
+  return false;
+}
+
+void CControlPointsManagerPatch::Render()
+{
+  int i,j;
+
+  m_pQglTable->m_pfn_qglColor3f(0, 1, 0);
+  m_pQglTable->m_pfn_qglPointSize(6);
+  m_pQglTable->m_pfn_qglBegin( GL_POINTS );
+  for ( i=0; i<m_pPatch->width; i++ )
+    for ( j=0; j<m_pPatch->height; j++ )
+    {
+      if ( ManagerState == Drag && i == m_iDragPoint[0] && j == m_iDragPoint[1] )
+       m_pQglTable->m_pfn_qglColor3f(1, 0, 0);
+      m_pQglTable->m_pfn_qglVertex2f( m_pWorkPatch->ctrl[i][j].st[0], m_pWorkPatch->ctrl[i][j].st[1] );
+      m_pQglTable->m_pfn_qglColor3f(0, 1, 0);
+    }
+  m_pQglTable->m_pfn_qglEnd();
+}
+
+void CControlPointsManagerPatch::Commit()
+{
+  int i,j;
+  for ( i=0; i<m_pPatch->width; i++ )
+    for ( j=0; j<m_pPatch->height; j++ )
+    {
+      m_pPatch->ctrl[i][j].st[0] = m_pWorkPatch->ctrl[i][j].st[0];
+      m_pPatch->ctrl[i][j].st[1] = m_pWorkPatch->ctrl[i][j].st[1];
+    }
+}