source: projectionDesigner/trunk/projdesigner/src/gui/QGLViewerWidget.cpp @ 26

Last change on this file since 26 was 4, checked in by Torben Dannhauer, 15 years ago
File size: 13.0 KB
Line 
1#include <float.h>
2#include <QMouseEvent>
3
4#include "gui/QGLViewerWidget.h"
5
6#define INERTIA_MAX 5.0f
7#define INERTIA_THRESHOLD 0.2f
8
9using namespace gmtl;
10
11static void dom2vp(const QDomElement& parent, gmtl::Vec3f& center, gmtl::Quatf& rot, float& distance)
12{
13    if (parent.isNull())
14        return;
15
16    center[0] = parent.attribute("centerx", "0").toFloat();
17    center[1] = parent.attribute("centery", "0").toFloat();
18    center[2] = parent.attribute("centerz", "0").toFloat();
19    rot[0] = parent.attribute("rotx", "0").toFloat();
20    rot[1] = parent.attribute("roty", "0").toFloat();
21    rot[2] = parent.attribute("rotz", "0").toFloat();
22    rot[3] = parent.attribute("rotw", "1").toFloat();
23    distance = parent.attribute("distance", "1").toFloat();
24}
25
26static QDomElement vp2dom(QDomDocument& doc, const gmtl::Vec3f& center, const gmtl::Quatf& rot, float distance)
27{
28    QDomElement cm = doc.createElement("Camera");
29    cm.setAttribute("centerx", QString::number(center[0]));
30    cm.setAttribute("centery", QString::number(center[1]));
31    cm.setAttribute("centerz", QString::number(center[2]));
32    cm.setAttribute("rotx", QString::number(rot[0]));
33    cm.setAttribute("roty", QString::number(rot[1]));
34    cm.setAttribute("rotz", QString::number(rot[2]));
35    cm.setAttribute("rotw", QString::number(rot[3]));
36    cm.setAttribute("distance", QString::number(distance));
37    return cm;
38}
39
40QGLViewerWidget::QGLViewerWidget(QWidget* pParent, const QGLWidget* pShareWidget, Qt::WindowFlags f) : QGLWidget(pParent, pShareWidget, f)
41{
42    m_bPerspective = true;
43    m_fovy = 45.0f;
44    m_znear = 0.01f;
45    m_zfar = 100.0f;
46
47    m_bInertia = true;
48    m_animX = 0.0f;
49    m_animY = 0.0f;
50    m_bAnimating = false;
51
52    m_clearColor = QColor(64, 64, 64);
53    m_sceneSize = 10.0f;
54    m_bGridVisible = false;
55    m_bAxisVisible = false;
56    m_gridSize = 10.0f;
57    m_gridSubdiv = 10;
58
59    viewAll();
60
61    m_timer.setInterval(30);
62    connect(&m_timer, SIGNAL(timeout()), this, SLOT(timeout()));
63    m_timer.start();
64
65    setFocusPolicy(Qt::StrongFocus);
66}
67
68void QGLViewerWidget::setView(const gmtl::Vec3f& center, const gmtl::Quatf& rot, float distance)
69{
70    m_center = center;
71    m_rot = rot;
72    m_distance = distance;
73    m_matrix = makeTrans<Matrix44f>(m_center) * makeRot<Matrix44f>(m_rot) * makeTrans<Matrix44f>(Vec3f(0.0f, 0.0f, m_distance));
74    invert(m_matrix);
75
76    emit cameraChanged(center, rot, distance);
77}
78
79void QGLViewerWidget::init()
80{
81}
82
83void QGLViewerWidget::draw()
84{
85}
86
87void QGLViewerWidget::idle()
88{
89}
90
91void QGLViewerWidget::stop()
92{
93    m_pivotCenter = m_center;
94    m_pivotRot = m_rot;
95    m_pivotDistance = m_distance;
96    m_pivotOrthoScale = m_orthoScale;
97    m_animX = 0.0f;
98    m_animY = 0.0f;
99    m_bAnimating = false;
100}
101
102void QGLViewerWidget::centerView()
103{
104    stop();
105    m_center = Vec3f(0.0f, 0.0f, 0.0f);
106    m_rot = Quatf();
107    m_distance = 0.0f;
108    m_orthoScale = 0.25f;
109    setView(m_center, m_rot, m_distance);
110    updateGL();
111}
112
113void QGLViewerWidget::viewAll()
114{
115    stop();
116    m_center = Vec3f(0.0f, 0.0f, 0.0f);
117    if (m_bPerspective)
118        m_distance = m_sceneSize * 0.5f;
119    else
120        m_distance = 0.0f;
121    m_orthoScale = 0.25f;
122    setView(m_center, m_rot, m_distance);
123    updateGL();
124}
125
126void QGLViewerWidget::drawGrid()
127{
128    if (m_gridSubdiv == 0)
129        return;
130
131    glPushAttrib(GL_ALL_ATTRIB_BITS);
132    glDisable(GL_TEXTURE_2D);
133    glDisable(GL_LIGHTING);
134    glDisable(GL_BLEND);
135    glEnable(GL_DEPTH_TEST);
136    glLineWidth(1.0f);
137    glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
138    glBegin(GL_LINES);
139    for (int x=0; x<m_gridSubdiv+1; ++x)
140    {
141        glVertex3f(-m_gridSize/2.0f+m_gridSize/m_gridSubdiv*x, 0.0f, -m_gridSize/2.0f);
142        glVertex3f(-m_gridSize/2.0f+m_gridSize/m_gridSubdiv*x, 0.0f,  m_gridSize/2.0f);
143    }
144    for (int y=0; y<m_gridSubdiv+1; ++y)
145    {
146        glVertex3f(-m_gridSize/2.0f, 0.0f, -m_gridSize/2.0f+m_gridSize/m_gridSubdiv*y);
147        glVertex3f( m_gridSize/2.0f, 0.0f, -m_gridSize/2.0f+m_gridSize/m_gridSubdiv*y);
148    }
149    glEnd();
150    glPopAttrib();
151}
152
153void QGLViewerWidget::drawAxis()
154{
155    glPushAttrib(GL_ALL_ATTRIB_BITS);
156    glDisable(GL_TEXTURE_2D);
157    glDisable(GL_LIGHTING);
158    glDisable(GL_BLEND);
159    glEnable(GL_DEPTH_TEST);
160    glLineWidth(3.0f);
161    glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
162    glBegin(GL_LINES);
163    glVertex3f(0.0f, 0.0f, 0.0f);
164    glVertex3f(m_gridSize*0.6f, 0.0f, 0.0f);
165    glEnd();
166    glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
167    glBegin(GL_LINES);
168    glVertex3f(0.0f, 0.0f, 0.0f);
169    glVertex3f(0.0f, m_gridSize*0.6f, 0.0f);
170    glEnd();
171    glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
172    glBegin(GL_LINES);
173    glVertex3f(0.0f, 0.0f, 0.0f);
174    glVertex3f(0.0f, 0.0f, m_gridSize*0.6f);
175    glEnd();
176    glPopAttrib();
177}
178
179void QGLViewerWidget::initializeGL()
180{
181    init();
182}
183
184void QGLViewerWidget::paintGL()
185{
186    glViewport(0, 0, width(), height());
187
188    glClearColor((float)m_clearColor.red() / 255.0f,
189                 (float)m_clearColor.green() / 255.0f,
190                 (float)m_clearColor.blue() / 255.0f,
191                 1.0f);
192                 
193    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
194
195    glMatrixMode(GL_PROJECTION);
196    glLoadIdentity();
197
198    float aspect = 1.0f;
199    if (height() > 0)
200        aspect = (float)width()/height();
201    if (m_bPerspective)
202        gluPerspective(m_fovy, aspect, m_znear, m_zfar);
203    else
204    {
205        float size = m_sceneSize * m_orthoScale;
206        glOrtho(-size*aspect, size*aspect, -size, size, -m_sceneSize*4.0f, m_sceneSize*4.0f);
207    }
208
209    glMatrixMode(GL_MODELVIEW);
210    glLoadMatrixf(m_matrix.getData());
211
212    glEnable(GL_LIGHTING);
213    glEnable(GL_LIGHT0);
214    Vec3f pos = Vec3f(1.0f, 1.0f, 1.0f);
215    if (!_isnan(m_rot[0]))
216        pos = m_rot * pos;
217    GLfloat lposition[] = { pos[0], pos[1], pos[2], 0.0f };
218    GLfloat lambient[] = { 0.1f, 0.1f, 0.1f, 1.0f };
219    GLfloat ldiffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
220    glLightfv(GL_LIGHT0, GL_POSITION, lposition);
221    glLightfv(GL_LIGHT0, GL_AMBIENT, lambient);
222    glLightfv(GL_LIGHT0, GL_DIFFUSE, ldiffuse);
223
224    glEnable(GL_DEPTH_TEST);
225    glEnable(GL_COLOR_MATERIAL);
226    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
227
228    draw();
229
230    glDisable(GL_LIGHTING);
231
232    if (m_bGridVisible)
233        drawGrid();
234
235    if (m_bAxisVisible)
236        drawAxis();
237
238    glFlush();
239}
240
241void QGLViewerWidget::mousePressEvent(QMouseEvent* pEvent)
242{
243    m_timer.stop();
244
245    stop();
246
247    m_lastMousePos = pEvent->pos();
248    m_lastTime = QTime::currentTime();
249
250    setMouseTracking(true);
251}
252
253void QGLViewerWidget::mouseMoveEvent(QMouseEvent* pEvent)
254{
255    if (m_bPerspective && (pEvent->buttons() & Qt::LeftButton))
256    {
257        float delta = (float)m_lastTime.msecsTo(QTime::currentTime()) / 1000.0f;
258        float deltaX = ((float)(pEvent->x()-m_lastMousePos.x())/width()*90.0f) / 180.0f * Math::PI;
259        float deltaY = ((float)(pEvent->y()-m_lastMousePos.y())/height()*90.0f) / 180.0f * Math::PI;
260        if (delta != 0.0f && (fabs(deltaX / delta) > INERTIA_THRESHOLD || fabs(deltaY / delta) > INERTIA_THRESHOLD))
261        {
262            m_animX = deltaX / delta;
263            m_animY = deltaY / delta;
264            float length = sqrt(m_animX*m_animX+m_animY*m_animY);
265            if (length > INERTIA_MAX)
266            {
267                m_animX = m_animX / length * INERTIA_MAX;
268                m_animY = m_animY / length * INERTIA_MAX;
269            }
270        }
271        else
272        {
273            m_animX = 0.0f;
274            m_animY = 0.0f;
275        }
276        m_rot = m_pivotRot * make<Quatf>(AxisAnglef(-deltaX, Vec3f(0.0f, 1.0f, 0.0f))) *
277                             make<Quatf>(AxisAnglef(-deltaY, Vec3f(1.0f, 0.0f, 0.0f)));
278    }
279    else if (pEvent->buttons() & Qt::MidButton ||
280             (!m_bPerspective && pEvent->buttons() & Qt::LeftButton))
281    {
282        float deltaX = (float)(pEvent->x()-m_lastMousePos.x())/width();
283        float deltaY = (float)(pEvent->y()-m_lastMousePos.y())/height();
284        Vec3f panX = m_rot * Vec3f(-deltaX, 0.0f, 0.0f);
285        Vec3f panY = m_rot * Vec3f(0.0f, deltaY, 0.0f);
286        m_center = m_pivotCenter + panX + panY;
287    }
288    else if (m_bPerspective && (pEvent->buttons() & Qt::RightButton))
289    {
290        if (m_distance > 0.0f)
291        {
292            m_distance = m_pivotDistance - m_pivotDistance * (float)(pEvent->y()-m_lastMousePos.y())/height() * 1.0f;
293            if (m_distance < m_znear*2.0f)
294                m_distance = m_znear*2.0f;
295        }
296    }
297    else if (!m_bPerspective && (pEvent->buttons() & Qt::RightButton))
298    {
299        m_orthoScale = m_pivotOrthoScale - m_pivotOrthoScale * (float)(pEvent->y()-m_lastMousePos.y())/height() * 1.0f;
300        if (m_orthoScale < 0.01f)
301            m_orthoScale = 0.01f;
302    }
303
304    setView(m_center, m_rot, m_distance);
305    m_lastTime = QTime::currentTime();
306
307    updateGL();
308}
309
310void QGLViewerWidget::mouseReleaseEvent(QMouseEvent* pEvent)
311{
312    Q_UNUSED(pEvent);
313
314    if (m_lastTime.msecsTo(QTime::currentTime()) > 50 || !m_bInertia)
315    {
316        m_animX = 0.0f;
317        m_animY = 0.0f;
318        m_bAnimating = false;
319    }
320    if (m_animX != 0.0f || m_animY != 0.0f)
321        m_bAnimating = true;
322
323    setMouseTracking(false);
324
325    m_timer.start();
326}
327
328void QGLViewerWidget::wheelEvent(QWheelEvent* pEvent)
329{
330    if (m_bPerspective)
331    {
332        if (pEvent->delta() > 0.0f)
333            setView(m_center, m_rot, m_distance * 1.1f);
334        else
335            setView(m_center, m_rot, m_distance / 1.1f);
336    }
337    else
338    {
339        if (pEvent->delta() > 0.0f)
340            m_orthoScale *= 1.1f;
341        else
342            m_orthoScale /= 1.1f;
343        if (m_orthoScale < 0.01f)
344            m_orthoScale = 0.01f;
345    }
346
347    updateGL();
348}
349
350void QGLViewerWidget::keyReleaseEvent(QKeyEvent* pEvent)
351{
352    QGLWidget::keyReleaseEvent(pEvent);
353
354        switch (pEvent->key())
355        {
356        case Qt::Key_A:
357        setAxisVisible(!m_bAxisVisible);
358        updateGL();
359                break;
360        case Qt::Key_G:
361        setGridVisible(!m_bGridVisible);
362        updateGL();
363                break;
364        case Qt::Key_R:
365        viewAll();
366                break;
367        default:
368                return;
369        }
370}
371
372void QGLViewerWidget::timeout()
373{
374    if (m_bAnimating)
375    {
376        float delta = (float)m_lastTime.msecsTo(QTime::currentTime()) / 1000.0f;
377        Quatf deltaRot = 
378            make<Quatf>(AxisAnglef(-m_animX*delta, Vec3f(0.0f, 1.0f, 0.0f))) *
379            make<Quatf>(AxisAnglef(-m_animY*delta, Vec3f(1.0f, 0.0f, 0.0f)));
380        Quatf rot = m_rot * deltaRot;
381        if (!_isnan(rot[0]))
382            setView(m_center, rot, m_distance);
383        m_lastTime = QTime::currentTime();
384    }
385
386    idle();
387
388    if (m_bAnimating)
389        updateGL();
390}
391
392void QGLViewerWidget::initFromDOMElement(const QDomElement& element)
393{
394        if (!element.isNull())
395        {
396                QDomElement camera = element.firstChildElement("Camera");
397        dom2vp(camera, m_center, m_rot, m_distance);
398        m_bPerspective = (element.attribute("perspective", "true")=="true");
399        m_fovy = element.attribute("fovy", QString::number(45.0f)).toFloat();
400        m_orthoScale = element.attribute("orthoScale", QString::number(0.25f)).toFloat();
401        m_znear = element.attribute("near", QString::number(0.01f)).toFloat();
402        m_zfar = element.attribute("far", QString::number(100.0f)).toFloat();
403        m_bInertia = (element.attribute("inertia", "true")=="true");
404        m_clearColor = QColor(element.attribute("clearColor", QColor(64, 64, 64).name()));
405        m_bGridVisible = (element.attribute("grid", "true")=="true");
406        m_bAxisVisible = (element.attribute("axis", "true")=="true");
407        m_sceneSize = element.attribute("sceneSize", QString::number(10.0f)).toFloat();
408        if (!parentWidget())
409        {
410            move(element.attribute("x", QString::number(x())).toInt(), element.attribute("y", QString::number(y())).toInt());
411            resize(element.attribute("width", QString::number(width())).toInt(), element.attribute("height", QString::number(height())).toInt());
412        }
413        setView(m_center, m_rot, m_distance);
414        stop();
415        }
416}
417
418QDomElement QGLViewerWidget::domElement(const QString& name, QDomDocument& doc) const
419{
420        QDomElement de = doc.createElement(name);
421    de.appendChild(vp2dom(doc, m_center, m_rot, m_distance));
422    de.setAttribute("perspective", m_bPerspective?"true":"false");
423    de.setAttribute("fovy", m_fovy);
424    de.setAttribute("orthoScale", m_orthoScale);
425    de.setAttribute("near", m_znear);
426    de.setAttribute("far", m_zfar);
427    de.setAttribute("inertia", m_bInertia?"true":"false");
428    de.setAttribute("clearColor", m_clearColor.name());
429    de.setAttribute("grid", m_bGridVisible?"true":"false");
430    de.setAttribute("axis", m_bAxisVisible?"true":"false");
431    de.setAttribute("sceneSize", m_sceneSize);
432    if (!parentWidget())
433    {
434        de.setAttribute("x", x());
435        de.setAttribute("y", y());
436        de.setAttribute("width", width());
437        de.setAttribute("height", height());
438    }
439    return de;
440}
Note: See TracBrowser for help on using the repository browser.