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)
37 // store the initial config
38 memcpy(&m_RefPts, Pts, sizeof(CtrlPts_t));
40 memset(m_TM, 0, sizeof(float[2][3]));
44 m_TransOffset[0] = 0.0f;
45 m_TransOffset[1] = 0.0f;
46 m_TexSize[0] = TexSize[0];
47 m_TexSize[1] = TexSize[1];
48 m_pFaceData = pFaceData;
50 CControlPointsManager::Init(p2DView, pQglTable);
53 bool CControlPointsManagerBFace::OnLButtonDown(int xPos, int yPos)
55 if (ManagerState == Idle) {
58 // scan the point list to see if we selected something
59 for (i = 0; i < m_NumPoints; i++) {
60 if (m_p2DView->DoesSelect(xPos, yPos, m_pPts->data[i])) {
63 if (m_bGotAnchor && i == m_iAnchorPoint) {
64 // this means we selected the Anchor, so we'll translate
67 // perhaps we won't use translation, but we can compute it anyway
68 ComputeTransOffset(i);
70 // we have an Anchor and selected another point
71 m_Anchor[0] = m_pPts->data[m_iAnchorPoint][0];
72 m_Anchor[1] = m_pPts->data[m_iAnchorPoint][1];
76 // send a repaint message
83 bool CControlPointsManagerBFace::OnMouseMove(int xPos, int yPos)
85 if (ManagerState == Drag) {
87 // there's an anchor, we are rotating the shape
88 // we need to work in XY space for orthonormality
97 m_p2DView->GridForWindow(Pt, xPos, yPos);
98 V2[0] = Pt[0] - m_Anchor[0];
99 V2[1] = Pt[1] - m_Anchor[1];
101 V1[0] = m_RefPts.data[m_iDragPoint][0] - m_RefPts.data[m_iAnchorPoint][0];
102 V1[1] = m_RefPts.data[m_iDragPoint][1] - m_RefPts.data[m_iAnchorPoint][1];
104 // compute transformation from V1 to V2
105 // we need to work in XY orthonormal space
106 XYSpaceForSTSpace(V1, V1);
107 XYSpaceForSTSpace(V2, V2);
108 VectorNormalize(V2, V2);
109 VectorNormalize(V1, V1);
110 c = DotProduct(V1, V2);
111 CrossProduct(V1, V2, cross);
112 s = VectorLength(cross);
113 // we compute the transformation matrix in XY space
114 // reference position of the Anchor in XY space
115 XYSpaceForSTSpace(XYRefAnchor, m_RefPts.data[m_iAnchorPoint]);
116 // current position of the Anchor in XY space
117 XYSpaceForSTSpace(XYAnchor, m_Anchor);
118 // compute transformation matrix
126 XYTM[0][2] = -c * XYRefAnchor[0] - s * XYRefAnchor[1] + XYAnchor[0];
127 XYTM[1][2] = s * XYRefAnchor[0] - c * XYRefAnchor[1] + XYAnchor[1];
128 // express this transformation matrix in ST space
129 m_TM[0][0] = XYTM[0][0];
130 m_TM[1][0] = XYTM[1][0] * (float) m_TexSize[0] / (float) m_TexSize[1];
131 m_TM[0][1] = XYTM[0][1] * (float) m_TexSize[1] / (float) m_TexSize[0];
132 m_TM[1][1] = XYTM[1][1];
133 m_TM[0][2] = XYTM[0][2] / (float) m_TexSize[0];
134 m_TM[1][2] = XYTM[1][2] / (float) m_TexSize[1];
138 // no Anchor point is defined, we translate all points
139 m_p2DView->GridForWindow(m_pPts->data[m_iDragPoint], xPos, yPos);
140 m_TM[0][2] = m_pPts->data[m_iDragPoint][0] + m_TransOffset[0];
141 m_TM[1][2] = m_pPts->data[m_iDragPoint][1] + m_TransOffset[1];
145 // send a repaint message
146 g_pToolWnd->Redraw();
153 bool CControlPointsManagerBFace::OnLButtonUp(int x, int y)
155 if (ManagerState == Drag) {
156 // this button is gonna become our Anchor
158 m_iAnchorPoint = m_iDragPoint;
159 // let's get out of Drag mode
161 // send a repaint message
162 g_pToolWnd->Redraw();
168 void CControlPointsManagerBFace::render()
172 m_pQglTable->m_pfn_qglColor3f(0, 1, 0);
173 m_pQglTable->m_pfn_qglPointSize(6);
174 m_pQglTable->m_pfn_qglBegin(GL_POINTS);
175 for (i = 0; i < m_NumPoints; i++) {
176 if (ManagerState == Drag && i == m_iDragPoint) {
177 m_pQglTable->m_pfn_qglColor3f(1, 0, 0);
178 } else if (m_bGotAnchor && i == m_iAnchorPoint) {
179 m_pQglTable->m_pfn_qglColor3f(0, 0, 1);
181 m_pQglTable->m_pfn_qglVertex2f(m_pPts->data[i][0], m_pPts->data[i][1]);
182 m_pQglTable->m_pfn_qglColor3f(0, 1, 0);
184 m_pQglTable->m_pfn_qglEnd();
187 void CControlPointsManagerBFace::UpdateCtrlPts()
192 for (i = 0; i < m_NumPoints; i++) {
193 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];
194 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];
197 if (g_bPrefsUpdateCameraView) {
199 // tell Radiant to update
200 // NOTE: little speed optimisation, disable window updates, and only update camera view
201 g_FuncTable.m_pfnSetScreenUpdate(false);
202 g_SelectedFaceTable.m_pfnSetFaceInfo(0, m_pFaceData);
203 g_FuncTable.m_pfnSetScreenUpdate(true);
204 g_FuncTable.m_pfnSysUpdateWindows(W_CAMERA);
208 //++timo FIXME: we are using a global for the reference data, use a m_pCancelFaceData instead
209 void CControlPointsManagerBFace::Commit()
211 brushprimit_texdef_t aux;
212 aux.coords[0][0] = m_TM[0][0] * g_CancelFaceData.brushprimit_texdef.coords[0][0] +
213 m_TM[0][1] * g_CancelFaceData.brushprimit_texdef.coords[1][0];
214 aux.coords[0][1] = m_TM[0][0] * g_CancelFaceData.brushprimit_texdef.coords[0][1] +
215 m_TM[0][1] * g_CancelFaceData.brushprimit_texdef.coords[1][1];
216 aux.coords[0][2] = m_TM[0][0] * g_CancelFaceData.brushprimit_texdef.coords[0][2] +
217 m_TM[0][1] * g_CancelFaceData.brushprimit_texdef.coords[1][2] + m_TM[0][2];
218 aux.coords[1][0] = m_TM[1][0] * g_CancelFaceData.brushprimit_texdef.coords[0][0] +
219 m_TM[1][1] * g_CancelFaceData.brushprimit_texdef.coords[1][0];
220 aux.coords[1][1] = m_TM[1][0] * g_CancelFaceData.brushprimit_texdef.coords[0][1] +
221 m_TM[1][1] * g_CancelFaceData.brushprimit_texdef.coords[1][1];
222 aux.coords[1][2] = m_TM[1][0] * g_CancelFaceData.brushprimit_texdef.coords[0][2] +
223 m_TM[1][1] * g_CancelFaceData.brushprimit_texdef.coords[1][2] + m_TM[1][2];
224 memcpy(&m_pFaceData->brushprimit_texdef, &aux, sizeof(brushprimit_texdef_t));
227 void CControlPointsManagerBFace::ComputeTransOffset(int i)
229 // compute the translation offset used to counteract rotation
230 m_TransOffset[0] = -m_TM[0][0] * m_RefPts.data[i][0] - m_TM[0][1] * m_RefPts.data[i][1];
231 m_TransOffset[1] = -m_TM[1][0] * m_RefPts.data[i][0] - m_TM[1][1] * m_RefPts.data[i][1];
234 void CControlPointsManagerBFace::XYSpaceForSTSpace(float xy[2], const float st[2])
236 xy[0] = st[0] * (float) m_TexSize[0];
237 xy[1] = st[1] * (float) m_TexSize[1];
241 ======================================================================
243 ======================================================================
246 void CControlPointsManagerPatch::Init(patchMesh_t *pWorkPatch, C2DView *p2DView, OpenGLBinding *pQglTable,
249 CControlPointsManager::Init(p2DView, pQglTable);
251 m_pWorkPatch = pWorkPatch;
254 bool CControlPointsManagerPatch::OnLButtonDown(int xPos, int yPos)
256 if (ManagerState == Idle) {
259 // scan the point list to see if we selected something
260 for (i = 0; i < m_pPatch->width; i++) {
261 for (j = 0; j < m_pPatch->height; j++) {
262 if (m_p2DView->DoesSelect(xPos, yPos, m_pWorkPatch->ctrl[i][j].st)) {
269 // send a repaint message
270 g_pToolWnd->Redraw();
276 bool CControlPointsManagerPatch::OnMouseMove(int xPos, int yPos)
278 if (ManagerState == Drag) {
279 m_p2DView->GridForWindow(m_pWorkPatch->ctrl[m_iDragPoint[0]][m_iDragPoint[1]].st, xPos, yPos);
280 if (g_bPrefsUpdateCameraView) {
282 // ask to rebuild the patch display data
283 m_pPatch->bDirty = true;
284 // send a repaint to the camera window as well
285 g_FuncTable.m_pfnSysUpdateWindows(W_CAMERA);
287 // send a repaint message
288 g_pToolWnd->Redraw();
294 bool CControlPointsManagerPatch::OnLButtonUp(int x, int y)
296 if (ManagerState == Drag) {
298 // send a repaint message
299 g_pToolWnd->Redraw();
304 void CControlPointsManagerPatch::render()
308 m_pQglTable->m_pfn_qglColor3f(0, 1, 0);
309 m_pQglTable->m_pfn_qglPointSize(6);
310 m_pQglTable->m_pfn_qglBegin(GL_POINTS);
311 for (i = 0; i < m_pPatch->width; i++) {
312 for (j = 0; j < m_pPatch->height; j++) {
313 if (ManagerState == Drag && i == m_iDragPoint[0] && j == m_iDragPoint[1]) {
314 m_pQglTable->m_pfn_qglColor3f(1, 0, 0);
316 m_pQglTable->m_pfn_qglVertex2f(m_pWorkPatch->ctrl[i][j].st[0], m_pWorkPatch->ctrl[i][j].st[1]);
317 m_pQglTable->m_pfn_qglColor3f(0, 1, 0);
320 m_pQglTable->m_pfn_qglEnd();
323 void CControlPointsManagerPatch::Commit()
326 for (i = 0; i < m_pPatch->width; i++) {
327 for (j = 0; j < m_pPatch->height; j++) {
328 m_pPatch->ctrl[i][j].st[0] = m_pWorkPatch->ctrl[i][j].st[0];
329 m_pPatch->ctrl[i][j].st[1] = m_pWorkPatch->ctrl[i][j].st[1];