pulsaranimationwidget.cpp 12.7 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;
45 46 47
	m_quadricPulsarSpinAxis = NULL;
	m_quadricPulsarMagneticAxis1 = NULL;
	m_quadricPulsarMagneticAxis2 = NULL;
Oliver Bock's avatar
Oliver Bock committed
48

49 50
	m_pulsarTexture = 0;
	m_backgroundTexture = 0;
51

Oliver Bock's avatar
Oliver Bock committed
52
	m_framesPerSecond = 25;
53

54
	resetParameters();
55

56
	m_cameraInteraction = false;
57 58
	m_mouseLastX = 0;
	m_mouseLastY = 0;
Oliver Bock's avatar
Oliver Bock committed
59 60
	m_mouseAngleH = 90.0f;
	m_mouseAngleV = 30.f;
61
	m_cameraZoom = 15.0f;
62 63 64
	m_cameraZoomLBound = 2.0f;

	updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
Oliver Bock's avatar
Oliver Bock committed
65 66 67 68
}

PulsarAnimationWidget::~PulsarAnimationWidget()
{
69
	if(m_quadricPulsarOrbitPlane) gluDeleteQuadric(m_quadricPulsarOrbitPlane);
Oliver Bock's avatar
Oliver Bock committed
70 71 72
	if(m_quadricPulsar) gluDeleteQuadric(m_quadricPulsar);
	if(m_quadricPulsarCone1) gluDeleteQuadric(m_quadricPulsarCone1);
	if(m_quadricPulsarCone2) gluDeleteQuadric(m_quadricPulsarCone2);
73 74 75
	if(m_quadricPulsarSpinAxis) gluDeleteQuadric(m_quadricPulsarSpinAxis);
	if(m_quadricPulsarMagneticAxis1) gluDeleteQuadric(m_quadricPulsarMagneticAxis1);
	if(m_quadricPulsarMagneticAxis2) gluDeleteQuadric(m_quadricPulsarMagneticAxis2);
76 77 78

	if(m_pulsarTexture) deleteTexture(m_pulsarTexture);
	if(m_backgroundTexture) deleteTexture(m_backgroundTexture);
Oliver Bock's avatar
Oliver Bock committed
79 80 81 82
}

void PulsarAnimationWidget::initializeGL()
{
Oliver Bock's avatar
Oliver Bock committed
83 84 85
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClearDepth(1.0f);
	glDepthFunc(GL_LEQUAL);
86 87 88
	glEnable(GL_DEPTH_TEST);

	glShadeModel(GL_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
89 90
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

91
	GLfloat LightAmbient[] = { 0.3f, 0.3f, 0.3f, 1.0f };
Oliver Bock's avatar
Oliver Bock committed
92 93 94 95 96 97 98 99 100
	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);
101
	glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 50.0);
Oliver Bock's avatar
Oliver Bock committed
102
	glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
103
	glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 10.0);
Oliver Bock's avatar
Oliver Bock committed
104 105 106 107

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

109
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
110
	glEnable(GL_BLEND);
111 112

	m_quadricPulsarOrbitPlane = gluNewQuadric();
Oliver Bock's avatar
Oliver Bock committed
113 114 115
	m_quadricPulsar = gluNewQuadric();
    m_quadricPulsarCone1 = gluNewQuadric();
    m_quadricPulsarCone2 = gluNewQuadric();
116 117 118 119
    m_quadricPulsarSpinAxis = gluNewQuadric();
    m_quadricPulsarMagneticAxis1 = gluNewQuadric();
    m_quadricPulsarMagneticAxis2 = gluNewQuadric();

120
    gluQuadricNormals(m_quadricPulsarOrbitPlane, GLU_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
121 122 123
    gluQuadricNormals(m_quadricPulsar, GLU_SMOOTH);
    gluQuadricNormals(m_quadricPulsarCone1, GLU_SMOOTH);
    gluQuadricNormals(m_quadricPulsarCone2, GLU_SMOOTH);
124 125 126
    gluQuadricNormals(m_quadricPulsarSpinAxis, GLU_SMOOTH);
    gluQuadricNormals(m_quadricPulsarMagneticAxis1, GLU_SMOOTH);
    gluQuadricNormals(m_quadricPulsarMagneticAxis2, GLU_SMOOTH);
127

128
    // load textures
129
    m_pulsarTexture = bindTexture(QImage(":/textures/resources/texture_pulsar.png"), GL_TEXTURE_2D, GL_RGBA);
130
    m_backgroundTexture = bindTexture(QImage(":/textures/resources/texture_background.png"), GL_TEXTURE_2D, GL_RGBA);
131

132
    // use mipmapped textures
133 134 135
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);

Oliver Bock's avatar
Oliver Bock committed
136 137 138
    // enable 2D mapping (s/t coordinates, sphere map won't rotate texture!)
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
Oliver Bock's avatar
Oliver Bock committed
139 140 141 142
}

void PulsarAnimationWidget::resizeGL(int w, int h)
{
Oliver Bock's avatar
Oliver Bock committed
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
	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();

161 162
	gluLookAt(m_cameraPosX, m_cameraPosY, m_cameraPosZ,
			  0.0, 0.0, 0.0,
163
			  0.0, 1.0, 0.0);
Oliver Bock's avatar
Oliver Bock committed
164 165 166 167 168

	// 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 };
169
	static GLfloat low_shininess[] = { 2.5 };
170
	static GLfloat translucent[] = { 1.0, 1.0, 1.0, 0.33 };
171

Oliver Bock's avatar
Oliver Bock committed
172 173 174 175 176
	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
177

Oliver Bock's avatar
Oliver Bock committed
178
	glPushMatrix();
179 180 181 182
		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
183 184 185
	glPopMatrix();

	glPushMatrix();
186 187 188 189 190
		glTranslatef(sin(m_orbitRotationAngle * deg2rad) * m_pulsarOrbitRadius,
					 0.0f,
					 cos(m_orbitRotationAngle * deg2rad) * m_pulsarOrbitRadius);

		glPushMatrix();
191 192 193 194 195
			// enable texture coordinates and bind texture
	        glEnable(GL_TEXTURE_GEN_S);
	        glEnable(GL_TEXTURE_GEN_T);
	        glBindTexture(GL_TEXTURE_2D, m_pulsarTexture);

196 197 198 199 200 201 202 203 204 205
			if(m_cameraInteraction) {
				glPushMatrix();
					glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
					glRotatef(90.0, 1.0f, 0.0f, 0.0f);
					glRotatef(-m_pulsarSpinAxisInclination, 0.0f, 1.0f, 0.0f);
					glTranslatef(0.0f, 0.0f, -5.0f);
					gluCylinder(m_quadricPulsarSpinAxis, 0.05f, 0.05f, 10.0f, 32, 1);
				glPopMatrix();
			}

206
			glRotatef(m_pulsarRotationAngle, 0.0f, 1.0f, 0.0f);
207
			glRotatef(m_pulsarSpinAxisInclination, 1.0f, 0.0f, 0.0f);
208 209 210 211

		    glEnable(GL_TEXTURE_2D);
			glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
212
			gluSphere(m_quadricPulsar, 1.0f, 32, 32);
213 214 215 216 217

			// disable texture coordinates
	        glDisable(GL_TEXTURE_GEN_S);
	        glDisable(GL_TEXTURE_GEN_T);
	        glDisable(GL_TEXTURE_2D);
218 219
		glPopMatrix();

220 221 222 223 224 225 226
		// 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_SPECULAR, coneSpecular);

227
		glPushMatrix();
228
			glRotatef(m_pulsarRotationAngle - 90.0f, 0.0f, 1.0f, 0.0f);
229
			glRotatef(-m_pulsarMagneticAxisInclination - m_pulsarSpinAxisInclination + 90.0f, 1.0f, 0.0f, 0.0f);
230 231 232 233 234 235

			if(m_cameraInteraction) {
				glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
				gluCylinder(m_quadricPulsarMagneticAxis1, 0.05f, 0.05f, 5.0f, 32, 1);
			}

236
			glTranslatef(0.0f, 0.0f, -4.0f);
237 238 239

			glMaterialfv(GL_FRONT, GL_AMBIENT, coneAmbient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, coneDiffuse);
240 241 242 243
			gluCylinder(m_quadricPulsarCone1, 0.5f, 0.0f, 3.0f, 32, 32);
		glPopMatrix();

		glPushMatrix();
244
			glRotatef(m_pulsarRotationAngle + 90.0f, 0.0f, 1.0f, 0.0f);
245
			glRotatef(m_pulsarMagneticAxisInclination + m_pulsarSpinAxisInclination - 90.0f, 1.0f, 0.0f, 0.0f);
246 247 248 249 250 251

			if(m_cameraInteraction) {
				glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
				gluCylinder(m_quadricPulsarMagneticAxis2, 0.05f, 0.05f, 5.0f, 32, 1);
			}

252
			glTranslatef(0.0f, 0.0f, -4.0f);
253 254 255

			glMaterialfv(GL_FRONT, GL_AMBIENT, coneAmbient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, coneDiffuse);
256 257
			gluCylinder(m_quadricPulsarCone2, 0.5f, 0.0f, 3.0f, 32, 32);
		glPopMatrix();
Oliver Bock's avatar
Oliver Bock committed
258
	glPopMatrix();
259 260

	if(m_cameraInteraction) {
261
		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
262 263 264 265 266 267 268 269 270

		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
271 272
}

Oliver Bock's avatar
Oliver Bock committed
273 274
void PulsarAnimationWidget::runAnimation()
{
Oliver Bock's avatar
Oliver Bock committed
275
	m_frameTimer.start(1000.0f / m_framesPerSecond);
Oliver Bock's avatar
Oliver Bock committed
276
}
Oliver Bock's avatar
Oliver Bock committed
277

Oliver Bock's avatar
Oliver Bock committed
278 279 280 281 282 283 284 285
void PulsarAnimationWidget::pauseAnimation()
{
	m_frameTimer.stop();
}

void PulsarAnimationWidget::stopAnimation()
{
	m_frameTimer.stop();
286
	resetParameters();
Oliver Bock's avatar
Oliver Bock committed
287 288 289 290

	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
291
void PulsarAnimationWidget::updateFrame()
Oliver Bock's avatar
Oliver Bock committed
292
{
Oliver Bock's avatar
Oliver Bock committed
293 294 295
	m_pulsarRotationAngle += m_pulsarRotationDelta;
	if(m_pulsarRotationAngle > 360) {
		m_pulsarRotationAngle = 0.0f;
Oliver Bock's avatar
Oliver Bock committed
296
	}
Oliver Bock's avatar
Oliver Bock committed
297 298 299
	m_orbitRotationAngle += m_orbitRotationDelta;
	if(m_orbitRotationAngle > 360) {
		m_orbitRotationAngle = 0.0f;
Oliver Bock's avatar
Oliver Bock committed
300 301
	}

Oliver Bock's avatar
Oliver Bock committed
302
	updateGL();
303 304
}

305 306
void PulsarAnimationWidget::mousePressEvent(QMouseEvent *event)
{
307 308
	Q_UNUSED(event);

309 310 311 312
	m_cameraInteraction = true;
	updateGL();
}

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
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)
{
346 347
	Q_UNUSED(event);

348 349
	m_mouseLastX = 0;
	m_mouseLastY = 0;
350 351
	m_cameraInteraction = false;
	updateGL();
352 353 354 355 356 357
}

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
358
	m_cameraPosZ = cos(angleH * deg2rad) * cos(fabs(angleV * deg2rad)) * zoom;
359 360 361 362

	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
363 364 365 366 367
void PulsarAnimationWidget::setFramePerSecond(const unsigned int fps)
{
	m_framesPerSecond = fps;
}

Oliver Bock's avatar
Oliver Bock committed
368
void PulsarAnimationWidget::setPulsarRotationDelta(const float frequency)
Oliver Bock's avatar
Oliver Bock committed
369
{
Oliver Bock's avatar
Oliver Bock committed
370
	m_pulsarRotationDelta = (360.0f * frequency) / m_framesPerSecond;
Oliver Bock's avatar
Oliver Bock committed
371
}
372

Oliver Bock's avatar
Oliver Bock committed
373
void PulsarAnimationWidget::setOrbitRotationDelta(const float frequency)
374
{
Oliver Bock's avatar
Oliver Bock committed
375
	m_orbitRotationDelta = (360.0f * frequency) / m_framesPerSecond;
376 377
}

Oliver Bock's avatar
Oliver Bock committed
378
void PulsarAnimationWidget::setOrbitRadius(const float radius)
379
{
380 381 382
	// for the time being both have the same orbit (mass)
	m_pulsarOrbitRadius = radius;
	m_companionOrbitRadius = radius;
383
}
384

385 386 387 388 389 390 391
void PulsarAnimationWidget::setPulsarSpinAxisInclination(const int degrees)
{
	m_pulsarSpinAxisInclination = degrees;

	updateGL();
}

392 393 394 395 396 397
void PulsarAnimationWidget::setPulsarMagneticAxisInclination(const int degrees)
{
	m_pulsarMagneticAxisInclination = degrees;

	updateGL();
}
398 399 400 401 402 403

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