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;
}