/****************************************************************************** * Copyright (C) 2008 by Oliver Bock * * oliver.bock[AT]aei.mpg.de * * * * This file is part of PulsatingScience. * * * * PulsatingScience 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, version 3 of the License. * * * * PulsatingScience 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 PulsatingScience. If not, see . * * * ******************************************************************************/ #include "pulsaranimationwidget.h" const float PulsarAnimationWidget::deg2rad = PI/180.0f; PulsarAnimationWidget::PulsarAnimationWidget(QWidget *parent) : QGLWidget(QGLFormat(QGL::AlphaChannel | QGL::SampleBuffers), parent), m_frameTimer() { if(!format().rgba()) { qWarning("Sorry, no RGBA support..."); } if(!format().alpha()) { qWarning("Sorry, no alpha channel support..."); } if(!format().sampleBuffers()) { qWarning("Sorry, no multisampling support..."); } connect(&m_frameTimer, SIGNAL(timeout()), this, SLOT(updateFrame())); m_quadricPulsarOrbitPlane = NULL; m_quadricPulsar = NULL; m_quadricPulsarCone1 = NULL; m_quadricPulsarCone2 = NULL; m_framesPerSecond = 25; resetParameters(); m_cameraInteraction = false; m_mouseLastX = 0; m_mouseLastY = 0; m_mouseAngleH = 90.0f; m_mouseAngleV = 30.f; m_cameraZoom = 15.0f; m_cameraZoomLBound = 2.0f; updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom); } PulsarAnimationWidget::~PulsarAnimationWidget() { if(m_quadricPulsarOrbitPlane) gluDeleteQuadric(m_quadricPulsarOrbitPlane); if(m_quadricPulsar) gluDeleteQuadric(m_quadricPulsar); if(m_quadricPulsarCone1) gluDeleteQuadric(m_quadricPulsarCone1); if(m_quadricPulsarCone2) gluDeleteQuadric(m_quadricPulsarCone2); } void PulsarAnimationWidget::initializeGL() { glClearColor(0.0, 0.0, 0.0, 0.0); glClearDepth(1.0f); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); GLfloat LightAmbient[] = { 0.3f, 0.3f, 0.3f, 1.0f }; GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat LightSpecular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat LightPosition[] = { 0.0f, 0.0f, 3.0f, 1.0f }; GLfloat spot_direction[] = { 0.0, 0.0, -1.0 }; glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient); glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpecular); glLightfv(GL_LIGHT0, GL_POSITION, LightPosition); glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 50.0); glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction); glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 10.0); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); m_quadricPulsarOrbitPlane = gluNewQuadric(); m_quadricPulsar = gluNewQuadric(); m_quadricPulsarCone1 = gluNewQuadric(); m_quadricPulsarCone2 = gluNewQuadric(); gluQuadricNormals(m_quadricPulsarOrbitPlane, GLU_SMOOTH); gluQuadricNormals(m_quadricPulsar, GLU_SMOOTH); gluQuadricNormals(m_quadricPulsarCone1, GLU_SMOOTH); gluQuadricNormals(m_quadricPulsarCone2, GLU_SMOOTH); } void PulsarAnimationWidget::resizeGL(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, (GLfloat)w / (GLfloat)h, 0.1f, 100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void PulsarAnimationWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(m_cameraPosX, m_cameraPosY, m_cameraPosZ, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // TODO: should be located elsewhere static GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 }; static GLfloat mat_diffuse[] = { 0.5, 0.5, 0.5, 1.0 }; static GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; static GLfloat low_shininess[] = { 5.0 }; glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); glPushMatrix(); glTranslatef(sin((m_orbitRotationAngle + 180) * deg2rad) * m_companionOrbitRadius, 0.0f, cos((m_orbitRotationAngle + 180) * deg2rad) * m_companionOrbitRadius); gluSphere(m_quadricPulsar, 1.0f, 32, 32); glPopMatrix(); glPushMatrix(); glTranslatef(sin(m_orbitRotationAngle * deg2rad) * m_pulsarOrbitRadius, 0.0f, cos(m_orbitRotationAngle * deg2rad) * m_pulsarOrbitRadius); glPushMatrix(); glRotatef(m_pulsarRotationAngle, 0.0f, 1.0f, 0.0f); glRotatef(m_pulsarSpinAxisInclination, 1.0f, 0.0f, 0.0f); gluSphere(m_quadricPulsar, 1.0f, 32, 32); glPopMatrix(); // TODO: should be located elsewhere static GLfloat coneAmbient[] = { 1.0, 1.0, 0.0, 1.0 }; static GLfloat coneDiffuse[] = { 1.0, 1.0, 0.0, 1.0 }; static GLfloat coneSpecular[] = { 1.0, 1.0, 0.5, 1.0 }; glMaterialfv(GL_FRONT, GL_AMBIENT, coneAmbient); glMaterialfv(GL_FRONT, GL_DIFFUSE, coneDiffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, coneSpecular); glPushMatrix(); glRotatef(m_pulsarRotationAngle - 90.0f, 0.0f, 1.0f, 0.0f); glRotatef(-m_pulsarMagneticAxisInclination - m_pulsarSpinAxisInclination + 90.0f, 1.0f, 0.0f, 0.0f); glTranslatef(0.0f, 0.0f, -4.0f); gluCylinder(m_quadricPulsarCone1, 0.5f, 0.0f, 3.0f, 32, 32); glPopMatrix(); glPushMatrix(); glRotatef(m_pulsarRotationAngle + 90.0f, 0.0f, 1.0f, 0.0f); glRotatef(m_pulsarMagneticAxisInclination + m_pulsarSpinAxisInclination - 90.0f, 1.0f, 0.0f, 0.0f); glTranslatef(0.0f, 0.0f, -4.0f); gluCylinder(m_quadricPulsarCone2, 0.5f, 0.0f, 3.0f, 32, 32); glPopMatrix(); glPopMatrix(); if(m_cameraInteraction) { static GLfloat pulsarOrbitAmbientDiffuse[] = { 1.0, 1.0, 1.0, 0.33 }; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, pulsarOrbitAmbientDiffuse); glPushMatrix(); glRotatef(90.0f, 1.0f, 0.0f, 0.0f); gluDisk(m_quadricPulsarOrbitPlane, m_pulsarOrbitRadius * 0.9f, m_pulsarOrbitRadius * 1.1f, 64, 1); glPopMatrix(); } } void PulsarAnimationWidget::runAnimation() { m_frameTimer.start(1000.0f / m_framesPerSecond); } void PulsarAnimationWidget::pauseAnimation() { m_frameTimer.stop(); } void PulsarAnimationWidget::stopAnimation() { m_frameTimer.stop(); resetParameters(); updateGL(); } void PulsarAnimationWidget::updateFrame() { m_pulsarRotationAngle += m_pulsarRotationDelta; if(m_pulsarRotationAngle > 360) { m_pulsarRotationAngle = 0.0f; } m_orbitRotationAngle += m_orbitRotationDelta; if(m_orbitRotationAngle > 360) { m_orbitRotationAngle = 0.0f; } updateGL(); } void PulsarAnimationWidget::mousePressEvent(QMouseEvent *event) { Q_UNUSED(event); m_cameraInteraction = true; updateGL(); } void PulsarAnimationWidget::mouseMoveEvent(QMouseEvent *event) { Qt::MouseButtons buttons = event->buttons(); if((buttons & Qt::LeftButton) == Qt::LeftButton) { if(m_mouseLastX != 0) { m_mouseAngleH -= (m_mouseLastX - event->x()) / 2; m_mouseAngleH = m_mouseAngleH < 360? m_mouseAngleH : 0; } if(m_mouseLastY != 0) { m_mouseAngleV -= (m_mouseLastY - event->y()) / 2; m_mouseAngleV = m_mouseAngleV < 90? m_mouseAngleV : 90; m_mouseAngleV = m_mouseAngleV > -90? m_mouseAngleV : -90; } m_mouseLastX = event->x(); m_mouseLastY = event->y(); } else if((buttons & Qt::RightButton) == Qt::RightButton) { if(m_mouseLastY != 0) { m_cameraZoom -= (m_mouseLastY - event->y()) / 2; m_cameraZoom = m_cameraZoom >= m_cameraZoomLBound? m_cameraZoom : m_cameraZoomLBound; updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom); } m_mouseLastY = event->y(); } updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom); } void PulsarAnimationWidget::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event); m_mouseLastX = 0; m_mouseLastY = 0; m_cameraInteraction = false; updateGL(); } void PulsarAnimationWidget::updateCameraPosition(const int angleH, const int angleV, const float zoom) { m_cameraPosX = sin(angleH * deg2rad) * zoom; m_cameraPosY = sin(angleV * deg2rad) * zoom; m_cameraPosZ = cos(angleH * deg2rad) * cos(fabs(angleV * deg2rad)) * zoom; updateGL(); } void PulsarAnimationWidget::setFramePerSecond(const unsigned int fps) { m_framesPerSecond = fps; } void PulsarAnimationWidget::setPulsarRotationDelta(const float frequency) { m_pulsarRotationDelta = (360.0f * frequency) / m_framesPerSecond; } void PulsarAnimationWidget::setOrbitRotationDelta(const float frequency) { m_orbitRotationDelta = (360.0f * frequency) / m_framesPerSecond; } void PulsarAnimationWidget::setOrbitRadius(const float radius) { // for the time being both have the same orbit (mass) m_pulsarOrbitRadius = radius; m_companionOrbitRadius = radius; } void PulsarAnimationWidget::setPulsarSpinAxisInclination(const int degrees) { m_pulsarSpinAxisInclination = degrees; updateGL(); } void PulsarAnimationWidget::setPulsarMagneticAxisInclination(const int degrees) { m_pulsarMagneticAxisInclination = degrees; updateGL(); } void PulsarAnimationWidget::resetParameters() { m_pulsarRotationAngle = 0.0f; m_orbitRotationAngle = 0.0f; }