]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/textool/ControlPointsManager.cpp
reformat code! now the code is only ugly on the *inside*
[xonotic/netradiant.git] / plugins / textool / ControlPointsManager.cpp
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
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.
11
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.
16
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
20  */
21
22 //-----------------------------------------------------------------------------
23 //
24 // DESCRIPTION:
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
27 //
28
29 #include "StdAfx.h"
30
31 void CControlPointsManagerBFace::Init(int iPts, CtrlPts_t *Pts, C2DView *p2DView, int TexSize[2],
32                                       _QERFaceData *pFaceData, OpenGLBinding *pQglTable)
33 {
34     ManagerState = Idle;
35     m_NumPoints = iPts;
36     m_pPts = Pts;
37     // store the initial config
38     memcpy(&m_RefPts, Pts, sizeof(CtrlPts_t));
39     // init TM
40     memset(m_TM, 0, sizeof(float[2][3]));
41     m_TM[0][0] = 1.0f;
42     m_TM[1][1] = 1.0f;
43     m_bGotAnchor = false;
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;
49
50     CControlPointsManager::Init(p2DView, pQglTable);
51 }
52
53 bool CControlPointsManagerBFace::OnLButtonDown(int xPos, int yPos)
54 {
55     if (ManagerState == Idle) {
56         int i;
57
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])) {
61                 m_iDragPoint = i;
62                 ManagerState = Drag;
63                 if (m_bGotAnchor && i == m_iAnchorPoint) {
64                     // this means we selected the Anchor, so we'll translate
65                     m_bGotAnchor = false;
66                 }
67                 // perhaps we won't use translation, but we can compute it anyway
68                 ComputeTransOffset(i);
69                 if (m_bGotAnchor) {
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];
73                 }
74             }
75         }
76         // send a repaint message
77         g_pToolWnd->Redraw();
78         return true;
79     }
80     return false;
81 }
82
83 bool CControlPointsManagerBFace::OnMouseMove(int xPos, int yPos)
84 {
85     if (ManagerState == Drag) {
86         if (m_bGotAnchor) {
87             // there's an anchor, we are rotating the shape
88             // we need to work in XY space for orthonormality
89             float Pt[2];
90             vec3_t V1, V2;
91             vec3_t cross;
92             float c, s;
93             // used in XY space
94             float XYTM[2][3];
95             float XYRefAnchor[2];
96             float XYAnchor[2];
97             m_p2DView->GridForWindow(Pt, xPos, yPos);
98             V2[0] = Pt[0] - m_Anchor[0];
99             V2[1] = Pt[1] - m_Anchor[1];
100             V2[2] = 0.0f;
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];
103             V1[2] = 0.0f;
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
119             XYTM[0][0] = c;
120             XYTM[1][1] = c;
121             if (cross[2] > 0) {
122                 s *= -1.0f;
123             }
124             XYTM[0][1] = s;
125             XYTM[1][0] = -s;
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];
135             // update all points
136             UpdateCtrlPts();
137         } else {
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];
142             // update all points
143             UpdateCtrlPts();
144         }
145         // send a repaint message
146         g_pToolWnd->Redraw();
147         return true;
148     }
149
150     return false;
151 }
152
153 bool CControlPointsManagerBFace::OnLButtonUp(int x, int y)
154 {
155     if (ManagerState == Drag) {
156         // this button is gonna become our Anchor
157         m_bGotAnchor = true;
158         m_iAnchorPoint = m_iDragPoint;
159         // let's get out of Drag mode
160         ManagerState = Idle;
161         // send a repaint message
162         g_pToolWnd->Redraw();
163         return true;
164     }
165     return false;
166 }
167
168 void CControlPointsManagerBFace::render()
169 {
170     int i;
171
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);
180         }
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);
183     }
184     m_pQglTable->m_pfn_qglEnd();
185 }
186
187 void CControlPointsManagerBFace::UpdateCtrlPts()
188 {
189     int i;
190
191     // update all points
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];
195     }
196
197     if (g_bPrefsUpdateCameraView) {
198         Commit();
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);
205     }
206 }
207
208 //++timo FIXME: we are using a global for the reference data, use a m_pCancelFaceData instead
209 void CControlPointsManagerBFace::Commit()
210 {
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));
225 }
226
227 void CControlPointsManagerBFace::ComputeTransOffset(int i)
228 {
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];
232 }
233
234 void CControlPointsManagerBFace::XYSpaceForSTSpace(float xy[2], const float st[2])
235 {
236     xy[0] = st[0] * (float) m_TexSize[0];
237     xy[1] = st[1] * (float) m_TexSize[1];
238 }
239
240 /*
241    ======================================================================
242    patch manager
243    ======================================================================
244  */
245
246 void CControlPointsManagerPatch::Init(patchMesh_t *pWorkPatch, C2DView *p2DView, OpenGLBinding *pQglTable,
247                                       patchMesh_t *pPatch)
248 {
249     CControlPointsManager::Init(p2DView, pQglTable);
250     m_pPatch = pPatch;
251     m_pWorkPatch = pWorkPatch;
252 }
253
254 bool CControlPointsManagerPatch::OnLButtonDown(int xPos, int yPos)
255 {
256     if (ManagerState == Idle) {
257         int i, j;
258
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)) {
263                     m_iDragPoint[0] = i;
264                     m_iDragPoint[1] = j;
265                     ManagerState = Drag;
266                 }
267             }
268         }
269         // send a repaint message
270         g_pToolWnd->Redraw();
271         return true;
272     }
273     return false;
274 }
275
276 bool CControlPointsManagerPatch::OnMouseMove(int xPos, int yPos)
277 {
278     if (ManagerState == Drag) {
279         m_p2DView->GridForWindow(m_pWorkPatch->ctrl[m_iDragPoint[0]][m_iDragPoint[1]].st, xPos, yPos);
280         if (g_bPrefsUpdateCameraView) {
281             Commit();
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);
286         }
287         // send a repaint message
288         g_pToolWnd->Redraw();
289         return true;
290     }
291     return false;
292 }
293
294 bool CControlPointsManagerPatch::OnLButtonUp(int x, int y)
295 {
296     if (ManagerState == Drag) {
297         ManagerState = Idle;
298         // send a repaint message
299         g_pToolWnd->Redraw();
300     }
301     return false;
302 }
303
304 void CControlPointsManagerPatch::render()
305 {
306     int i, j;
307
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);
315             }
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);
318         }
319     }
320     m_pQglTable->m_pfn_qglEnd();
321 }
322
323 void CControlPointsManagerPatch::Commit()
324 {
325     int i, j;
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];
330         }
331     }
332 }