pulsaranimationwidget.cpp 10.9 KB
Newer Older
Oliver Bock's avatar
Oliver Bock committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/******************************************************************************
 *   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 <http://www.gnu.org/licenses/>. *
 *                                                                            *
 ******************************************************************************/

#include "pulsaranimationwidget.h"

23 24
const float PulsarAnimationWidget::deg2rad = PI/180.0f;

Oliver Bock's avatar
Oliver Bock committed
25
PulsarAnimationWidget::PulsarAnimationWidget(QWidget *parent) :
Oliver Bock's avatar
Oliver Bock committed
26
	QGLWidget(QGLFormat(QGL::AlphaChannel | QGL::SampleBuffers), parent),
Oliver Bock's avatar
Oliver Bock committed
27
	m_frameTimer()
Oliver Bock's avatar
Oliver Bock committed
28
{
29 30 31 32 33 34
	if(!format().rgba()) {
		qWarning("Sorry, no RGBA support...");
	}
	if(!format().alpha()) {
		qWarning("Sorry, no alpha channel support...");
	}
Oliver Bock's avatar
Oliver Bock committed
35 36 37
	if(!format().sampleBuffers()) {
		qWarning("Sorry, no multisampling support...");
	}
38

Oliver Bock's avatar
Oliver Bock committed
39
    connect(&m_frameTimer, SIGNAL(timeout()), this, SLOT(updateFrame()));
Oliver Bock's avatar
Oliver Bock committed
40

41
    m_quadricPulsarOrbitPlane = NULL;
42 43 44
	m_quadricPulsar = NULL;
	m_quadricPulsarCone1 = NULL;
	m_quadricPulsarCone2 = NULL;
Oliver Bock's avatar
Oliver Bock committed
45 46

	m_framesPerSecond = 25;
47

48
	resetParameters();
49

50
	m_cameraInteraction = false;
51 52
	m_mouseLastX = 0;
	m_mouseLastY = 0;
Oliver Bock's avatar
Oliver Bock committed
53 54
	m_mouseAngleH = 90.0f;
	m_mouseAngleV = 30.f;
55
	m_cameraZoom = 15.0f;
56 57 58
	m_cameraZoomLBound = 2.0f;

	updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
Oliver Bock's avatar
Oliver Bock committed
59 60 61 62
}

PulsarAnimationWidget::~PulsarAnimationWidget()
{
63
	if(m_quadricPulsarOrbitPlane) gluDeleteQuadric(m_quadricPulsarOrbitPlane);
Oliver Bock's avatar
Oliver Bock committed
64 65 66
	if(m_quadricPulsar) gluDeleteQuadric(m_quadricPulsar);
	if(m_quadricPulsarCone1) gluDeleteQuadric(m_quadricPulsarCone1);
	if(m_quadricPulsarCone2) gluDeleteQuadric(m_quadricPulsarCone2);
Oliver Bock's avatar
Oliver Bock committed
67 68 69 70
}

void PulsarAnimationWidget::initializeGL()
{
Oliver Bock's avatar
Oliver Bock committed
71 72 73
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClearDepth(1.0f);
	glDepthFunc(GL_LEQUAL);
74 75 76
	glEnable(GL_DEPTH_TEST);

	glShadeModel(GL_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
77 78
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

79
	GLfloat LightAmbient[] = { 0.3f, 0.3f, 0.3f, 1.0f };
Oliver Bock's avatar
Oliver Bock committed
80 81 82 83 84 85 86 87 88
	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);
89
	glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 50.0);
Oliver Bock's avatar
Oliver Bock committed
90
	glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
91
	glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 10.0);
Oliver Bock's avatar
Oliver Bock committed
92 93 94 95

	glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHTING);
Oliver Bock's avatar
Oliver Bock committed
96

97
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
98
	glEnable(GL_BLEND);
99 100

	m_quadricPulsarOrbitPlane = gluNewQuadric();
Oliver Bock's avatar
Oliver Bock committed
101 102 103
	m_quadricPulsar = gluNewQuadric();
    m_quadricPulsarCone1 = gluNewQuadric();
    m_quadricPulsarCone2 = gluNewQuadric();
104
    gluQuadricNormals(m_quadricPulsarOrbitPlane, GLU_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
105 106 107
    gluQuadricNormals(m_quadricPulsar, GLU_SMOOTH);
    gluQuadricNormals(m_quadricPulsarCone1, GLU_SMOOTH);
    gluQuadricNormals(m_quadricPulsarCone2, GLU_SMOOTH);
108 109 110 111 112 113 114 115 116 117 118

    // load pulsar texture
    m_pulsarTexture = bindTexture(QImage(":/textures/resources/texture_pulsar.png"), GL_TEXTURE_2D, GL_RGBA);

    // use mipmap filter
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);

    // enable 2D sphere mapping (s/t coordinates)
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
Oliver Bock's avatar
Oliver Bock committed
119 120 121 122
}

void PulsarAnimationWidget::resizeGL(int w, int h)
{
Oliver Bock's avatar
Oliver Bock committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
	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();

141 142
	gluLookAt(m_cameraPosX, m_cameraPosY, m_cameraPosZ,
			  0.0, 0.0, 0.0,
143
			  0.0, 1.0, 0.0);
Oliver Bock's avatar
Oliver Bock committed
144 145 146 147 148

	// 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 };
149
	static GLfloat low_shininess[] = { 2.5 };
150

Oliver Bock's avatar
Oliver Bock committed
151 152 153 154 155
	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);
Oliver Bock's avatar
Oliver Bock committed
156

Oliver Bock's avatar
Oliver Bock committed
157
	glPushMatrix();
158 159 160 161
		glTranslatef(sin((m_orbitRotationAngle + 180) * deg2rad) * m_companionOrbitRadius,
					 0.0f,
					 cos((m_orbitRotationAngle + 180) * deg2rad) * m_companionOrbitRadius);
		gluSphere(m_quadricPulsar, 1.0f, 32, 32);
Oliver Bock's avatar
Oliver Bock committed
162 163 164
	glPopMatrix();

	glPushMatrix();
165 166 167 168 169
		glTranslatef(sin(m_orbitRotationAngle * deg2rad) * m_pulsarOrbitRadius,
					 0.0f,
					 cos(m_orbitRotationAngle * deg2rad) * m_pulsarOrbitRadius);

		glPushMatrix();
170 171 172 173 174 175 176
			// enable texture coordinates and bind texture
		    glEnable(GL_TEXTURE_2D);
	        glEnable(GL_TEXTURE_GEN_S);
	        glEnable(GL_TEXTURE_GEN_T);
	        glBindTexture(GL_TEXTURE_2D, m_pulsarTexture);

	        // FIXME: how to rotate texture?
177
			glRotatef(m_pulsarRotationAngle, 0.0f, 1.0f, 0.0f);
178
			glRotatef(m_pulsarSpinAxisInclination, 1.0f, 0.0f, 0.0f);
179
			gluSphere(m_quadricPulsar, 1.0f, 32, 32);
180 181 182 183 184

			// disable texture coordinates
	        glDisable(GL_TEXTURE_GEN_S);
	        glDisable(GL_TEXTURE_GEN_T);
	        glDisable(GL_TEXTURE_2D);
185 186
		glPopMatrix();

187 188 189 190 191 192 193 194 195
		// 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);

196
		glPushMatrix();
197
			glRotatef(m_pulsarRotationAngle - 90.0f, 0.0f, 1.0f, 0.0f);
198
			glRotatef(-m_pulsarMagneticAxisInclination - m_pulsarSpinAxisInclination + 90.0f, 1.0f, 0.0f, 0.0f);
199 200 201 202 203
			glTranslatef(0.0f, 0.0f, -4.0f);
			gluCylinder(m_quadricPulsarCone1, 0.5f, 0.0f, 3.0f, 32, 32);
		glPopMatrix();

		glPushMatrix();
204
			glRotatef(m_pulsarRotationAngle + 90.0f, 0.0f, 1.0f, 0.0f);
205
			glRotatef(m_pulsarMagneticAxisInclination + m_pulsarSpinAxisInclination - 90.0f, 1.0f, 0.0f, 0.0f);
206 207 208
			glTranslatef(0.0f, 0.0f, -4.0f);
			gluCylinder(m_quadricPulsarCone2, 0.5f, 0.0f, 3.0f, 32, 32);
		glPopMatrix();
Oliver Bock's avatar
Oliver Bock committed
209
	glPopMatrix();
210 211 212 213 214 215 216 217 218 219 220 221 222

	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();
	}
Oliver Bock's avatar
Oliver Bock committed
223 224
}

Oliver Bock's avatar
Oliver Bock committed
225 226
void PulsarAnimationWidget::runAnimation()
{
Oliver Bock's avatar
Oliver Bock committed
227
	m_frameTimer.start(1000.0f / m_framesPerSecond);
Oliver Bock's avatar
Oliver Bock committed
228
}
Oliver Bock's avatar
Oliver Bock committed
229

Oliver Bock's avatar
Oliver Bock committed
230 231 232 233 234 235 236 237
void PulsarAnimationWidget::pauseAnimation()
{
	m_frameTimer.stop();
}

void PulsarAnimationWidget::stopAnimation()
{
	m_frameTimer.stop();
238
	resetParameters();
Oliver Bock's avatar
Oliver Bock committed
239 240 241 242

	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
243
void PulsarAnimationWidget::updateFrame()
Oliver Bock's avatar
Oliver Bock committed
244
{
Oliver Bock's avatar
Oliver Bock committed
245 246 247
	m_pulsarRotationAngle += m_pulsarRotationDelta;
	if(m_pulsarRotationAngle > 360) {
		m_pulsarRotationAngle = 0.0f;
Oliver Bock's avatar
Oliver Bock committed
248
	}
Oliver Bock's avatar
Oliver Bock committed
249 250 251
	m_orbitRotationAngle += m_orbitRotationDelta;
	if(m_orbitRotationAngle > 360) {
		m_orbitRotationAngle = 0.0f;
Oliver Bock's avatar
Oliver Bock committed
252 253
	}

Oliver Bock's avatar
Oliver Bock committed
254
	updateGL();
255 256
}

257 258
void PulsarAnimationWidget::mousePressEvent(QMouseEvent *event)
{
259 260
	Q_UNUSED(event);

261 262 263 264
	m_cameraInteraction = true;
	updateGL();
}

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
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)
{
298 299
	Q_UNUSED(event);

300 301
	m_mouseLastX = 0;
	m_mouseLastY = 0;
302 303
	m_cameraInteraction = false;
	updateGL();
304 305 306 307 308 309
}

void PulsarAnimationWidget::updateCameraPosition(const int angleH, const int angleV, const float zoom)
{
	m_cameraPosX = sin(angleH * deg2rad) * zoom;
	m_cameraPosY = sin(angleV * deg2rad) * zoom;
Oliver Bock's avatar
Oliver Bock committed
310
	m_cameraPosZ = cos(angleH * deg2rad) * cos(fabs(angleV * deg2rad)) * zoom;
311 312 313 314

	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
315 316 317 318 319
void PulsarAnimationWidget::setFramePerSecond(const unsigned int fps)
{
	m_framesPerSecond = fps;
}

Oliver Bock's avatar
Oliver Bock committed
320
void PulsarAnimationWidget::setPulsarRotationDelta(const float frequency)
Oliver Bock's avatar
Oliver Bock committed
321
{
Oliver Bock's avatar
Oliver Bock committed
322
	m_pulsarRotationDelta = (360.0f * frequency) / m_framesPerSecond;
Oliver Bock's avatar
Oliver Bock committed
323
}
324

Oliver Bock's avatar
Oliver Bock committed
325
void PulsarAnimationWidget::setOrbitRotationDelta(const float frequency)
326
{
Oliver Bock's avatar
Oliver Bock committed
327
	m_orbitRotationDelta = (360.0f * frequency) / m_framesPerSecond;
328 329
}

Oliver Bock's avatar
Oliver Bock committed
330
void PulsarAnimationWidget::setOrbitRadius(const float radius)
331
{
332 333 334
	// for the time being both have the same orbit (mass)
	m_pulsarOrbitRadius = radius;
	m_companionOrbitRadius = radius;
335
}
336

337 338 339 340 341 342 343
void PulsarAnimationWidget::setPulsarSpinAxisInclination(const int degrees)
{
	m_pulsarSpinAxisInclination = degrees;

	updateGL();
}

344 345 346 347 348 349
void PulsarAnimationWidget::setPulsarMagneticAxisInclination(const int degrees)
{
	m_pulsarMagneticAxisInclination = degrees;

	updateGL();
}
350 351 352 353 354 355

void PulsarAnimationWidget::resetParameters()
{
	m_pulsarRotationAngle = 0.0f;
	m_orbitRotationAngle = 0.0f;
}