OglViewerWidget.cpp 9.12 KB
Newer Older
1
#include "..\Header\OglViewerWidget.h"
Anakin's avatar
Anakin committed
2
#include "..\Header\MainWindow.h"
3
#include <QMouseEvent>
Anakin's avatar
Anakin committed
4 5
#include <QDropEvent>
#include <QMimeData>
6
#include <math.h>
Anakin's avatar
Anakin committed
7 8
#include <iostream>

Anakin's avatar
Anakin committed
9
#define DEFAULT_Z_DISTANCE -4.0
10

Anakin's avatar
Anakin committed
11 12 13 14

/////////////////////////////////////////////////////////////////////////
// public constructor/destructor

Anakin's avatar
Anakin committed
15 16 17 18
OglViewerWidget::OglViewerWidget(QWidget *parent)
	: QOpenGLWidget(parent)
	, m_dataEngine(0)
	, m_settings(new SettingsWindow(this))
19
{
20
	setFocus();
Anakin's avatar
Anakin committed
21
	m_translation.setZ(DEFAULT_Z_DISTANCE);
Anakin's avatar
Anakin committed
22
	setAcceptDrops(true);
Anakin's avatar
Anakin committed
23

24 25 26 27 28 29 30
}

OglViewerWidget::~OglViewerWidget()
{
	// Make sure the context is current when deleting the texture
	// and the buffers.
	makeCurrent();
Anakin's avatar
Anakin committed
31
	delete m_dataEngine;
32
	doneCurrent();
Anakin's avatar
Anakin committed
33 34

	delete m_settings;
35 36
}

Anakin's avatar
Anakin committed
37 38 39 40

/////////////////////////////////////////////////////////////////////////
// protected functions

41 42 43
void OglViewerWidget::mousePressEvent(QMouseEvent *e)
{
	// Save mouse press position
44 45 46 47 48 49 50
	m_mouse.position = QVector2D(e->localPos());

	// Which button has been pressed?
	if (e->button() == Qt::LeftButton)
		m_mouse.left = true;
	else if (e->button() == Qt::RightButton)
		m_mouse.right = true;
51 52 53 54
}

void OglViewerWidget::mouseReleaseEvent(QMouseEvent *e)
{
55 56 57 58 59
	if (e->button() == Qt::LeftButton)
		m_mouse.left = false;
	else if (e->button() == Qt::RightButton)
		m_mouse.right = false;
}
60

61 62 63 64 65 66
void OglViewerWidget::mouseMoveEvent(QMouseEvent *e)
{
	if (m_mouse.left)
	{
		// get the difference between last press and now
		QVector2D diff = QVector2D(e->localPos()) - m_mouse.position;
67

68 69
		// update the new position
		m_mouse.position = QVector2D(e->localPos());
70

71
		// calculate the rotation axis and rotate
Anakin's avatar
Anakin committed
72 73 74 75 76 77 78
		if (m_rotDirections.x && m_rotDirections.y && m_rotDirections.z)
		{
			m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(diff.y(), diff.x(), 0.0).normalized(), diff.length() * 0.5) * m_rotation;
		}
		else if (m_rotDirections.x && m_rotDirections.y && !m_rotDirections.z)
		{

Anakin's avatar
Anakin committed
79 80
			float pitch, yaw, roll;
			m_rotation.getEulerAngles(&pitch, &yaw, &roll);
Anakin's avatar
Anakin committed
81

Anakin's avatar
Anakin committed
82 83
			pitch += diff.y() * 0.5;
			yaw += diff.x() * 0.5;
Anakin's avatar
Anakin committed
84

Anakin's avatar
Anakin committed
85 86 87 88 89 90
			if (pitch > 89)
				pitch = 89;
			else if (pitch < -89)
				pitch = -89;

			m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll);
Anakin's avatar
Anakin committed
91 92 93 94 95 96 97 98 99 100 101 102 103 104

		}
		else if (m_rotDirections.x && !m_rotDirections.y && !m_rotDirections.z)
		{
			m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(0.0, 1.0, 0.0).normalized(), diff.x() * 0.5) * m_rotation;
		}
		else if (!m_rotDirections.x && m_rotDirections.y && !m_rotDirections.z)
		{
			m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(1.0, 0.0, 0.0).normalized(), diff.y() * 0.5) * m_rotation;
		}
		else if (!m_rotDirections.x && !m_rotDirections.y && m_rotDirections.z)
		{
			m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(0.0, 0.0, 1.0).normalized(), diff.x() * 0.5) * m_rotation;
		}
Anakin's avatar
Anakin committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
		else if (m_rotDirections.x && !m_rotDirections.y && m_rotDirections.z)
		{
			float pitch, yaw, roll;
			m_rotation.getEulerAngles(&pitch, &yaw, &roll);
			roll -= diff.y() * 0.5;
			yaw += diff.x() * 0.5;

			m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll);
		}
		else if (!m_rotDirections.x && m_rotDirections.y && m_rotDirections.z)
		{
			float pitch, yaw, roll;
			m_rotation.getEulerAngles(&pitch, &yaw, &roll);
			pitch += diff.y() * 0.5;
			roll += diff.x() * 0.5;

			if (pitch > 89)
				pitch = 89;
			else if (pitch < -89)
				pitch = -89;

			m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll);
		}
Anakin's avatar
Anakin committed
128 129

		
Anakin's avatar
Anakin committed
130 131 132 133 134 135 136 137 138 139 140 141 142 143
		// request an update
		update();
	}
	else if (m_mouse.right)
	{
		// get the difference between last press and now
		QVector2D diff = QVector2D(e->localPos()) - m_mouse.position;

		// update the new position
		m_mouse.position = QVector2D(e->localPos());

		// calculate the translation
		m_translation += {(float)(diff.x() * 0.01), (float)(diff.y() * -0.01), 0.0};

144 145 146
		// request an update
		update();
	}
147 148
}

Anakin's avatar
Anakin committed
149 150
void OglViewerWidget::wheelEvent(QWheelEvent *e)
{
Anakin's avatar
Anakin committed
151
	m_translation += {0.0, 0.0, (float)m_zSpeed * e->angleDelta().y() / 240};
Anakin's avatar
Anakin committed
152 153 154
	update();
}

Anakin's avatar
Anakin committed
155 156 157 158 159 160 161 162 163
void OglViewerWidget::dragEnterEvent(QDragEnterEvent *e)
{
	if (e->mimeData()->hasUrls())
		if(e->mimeData()->urls().size() == 1)
			if(e->mimeData()->urls().first().toLocalFile().endsWith(".msh"))
				e->acceptProposedAction();

}

Anakin's avatar
Anakin committed
164 165
void OglViewerWidget::dropEvent(QDropEvent * e)
{
Anakin's avatar
Anakin committed
166
	emit loadFile(e->mimeData()->urls().first().toLocalFile());
Anakin's avatar
Anakin committed
167 168
}

169
void OglViewerWidget::keyPressEvent(QKeyEvent *e)
170
{
171
	if (e->key() == Qt::Key_Space)
Anakin's avatar
Anakin committed
172
	{
Anakin's avatar
Anakin committed
173
		resetView();
Anakin's avatar
Anakin committed
174
	}
Anakin's avatar
Anakin committed
175 176 177 178
	else if (e->key() == Qt::Key_Escape)
	{
		parentWidget()->close();
	}
Anakin's avatar
Anakin committed
179 180 181 182 183
	else if (e->key() == Qt::Key_L)
	{
		updateLightPosition();
		update();
	}
Anakin's avatar
Anakin committed
184 185 186 187 188 189 190 191 192 193 194
	else if (e->key() == Qt::Key_Minus)
	{
		m_zSpeed -= 0.1;
		m_zSpeed < 0.09 ? m_zSpeed = 0 : NULL;
		emit sendMessage(QString("Zoom speed = %1%").arg(m_zSpeed * 100), 0);
	}
	else if (e->key() == Qt::Key_Plus)
	{
		m_zSpeed += 0.1;
		emit sendMessage(QString("Zoom speed = %1%").arg(m_zSpeed * 100), 0);
	}
195 196 197 198 199 200
}

void OglViewerWidget::initializeGL()
{
	initializeOpenGLFunctions();

201
	//glClearColor(0.5000f, 0.8000f, 1.0000f, 0.0000f);
202 203 204 205 206 207 208

	initShaders();

	// Enable depth buffer
	glEnable(GL_DEPTH_TEST);

	// Enable back face culling
Anakin's avatar
Anakin committed
209 210 211 212 213
	//glEnable(GL_CULL_FACE);

	// Enable transparency
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
214

215 216
	m_dataEngine = new GeometryEngine(this);
	setConnections();
217 218 219 220 221 222 223 224
}

void OglViewerWidget::resizeGL(int w, int h)
{
	// Calculate aspect ratio
	qreal aspect = qreal(w) / qreal(h ? h : 1);

	// Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
Anakin's avatar
Anakin committed
225
	const qreal zNear = 0.1, zFar = 100.0, fov = 45.0;
226 227

	// Reset projection
228
	m_projection.setToIdentity();
229 230

	// Set perspective projection
231
	m_projection.perspective(fov, aspect, zNear, zFar);
232 233 234 235
}

void OglViewerWidget::paintGL()
{
236 237 238 239 240 241
	if (m_backgroundColor[3] == 1.0)
	{
		glClearColor(m_backgroundColor[0], m_backgroundColor[1], m_backgroundColor[2], 0.0000f);
		m_backgroundColor[3] = 0.0;
	}

Anakin's avatar
Anakin committed
242 243 244
	// Clear color and depth buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

245
	// Calculate model view transformation
Anakin's avatar
Anakin committed
246
	QMatrix4x4 view;
Anakin's avatar
Anakin committed
247
	view.translate(m_translation);
Anakin's avatar
Anakin committed
248
	view.rotate(m_rotation);
249

Anakin's avatar
Anakin committed
250 251
	// Set view-projection matrix
	m_program.setUniformValue("vp_matrix", m_projection * view);
252

253 254
	// Set Light values
	m_program.setUniformValue("b_light", m_lightOn);
Anakin's avatar
Anakin committed
255 256
	m_program.setUniformValue("light.position", m_light.position);
	m_program.setUniformValue("light.intensities", m_light.intensities);
Anakin's avatar
Anakin committed
257 258 259 260 261 262 263
	m_program.setUniformValue("light.attenuationFactor", m_light.attenuationFactor);
	m_program.setUniformValue("light.ambientCoefficient", m_light.ambientCoefficient);

	// Set camera position
	QMatrix4x4 rotateBack;
	rotateBack.rotate(m_rotation.inverted());
	m_program.setUniformValue("cameraPosition", rotateBack * (-m_translation));
Anakin's avatar
Anakin committed
264

265
	// Draw cube geometry
Anakin's avatar
Anakin committed
266
	m_dataEngine->drawGeometry(&m_program, m_wireframe);
267
}
Anakin's avatar
Anakin committed
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291


/////////////////////////////////////////////////////////////////////////
// private functions

void OglViewerWidget::initShaders()
{
	// Compile vertex shader
	if (!m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vshader.glsl"))
		close();

	// Compile fragment shader
	if (!m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fshader.glsl"))
		close();

	// Link shader pipeline
	if (!m_program.link())
		close();

	// Bind shader pipeline for use
	if (!m_program.bind())
		close();
}

292 293 294
void OglViewerWidget::setConnections()
{
	connect(m_dataEngine, &GeometryEngine::requestResetView, this, &OglViewerWidget::resetView);
Anakin's avatar
Anakin committed
295 296
	connect(parentWidget(), SIGNAL(loadFile(QString)), m_dataEngine, SLOT(loadFile(QString)));
	connect(this, SIGNAL(loadFile(QString)), m_dataEngine, SLOT(loadFile(QString)));
Anakin's avatar
Anakin committed
297
	connect(m_dataEngine, SIGNAL(sendMessage(QString, int)), parentWidget(), SLOT(printMessage(QString, int)));
298
	connect(m_dataEngine, SIGNAL(requestUpdate()), this, SLOT(update()));
299
	connect(m_dataEngine, SIGNAL(sendFileInfo(QString, QVector<Material>*, int, int)), parentWidget(), SLOT(setFileInfo(QString, QVector<Material>*, int, int)));
Anakin's avatar
Anakin committed
300

301 302
}

Anakin's avatar
Anakin committed
303 304 305 306
void OglViewerWidget::updateLightPosition()
{
	QMatrix4x4 rotateBack;
	rotateBack.rotate(m_rotation.inverted());
Anakin's avatar
Anakin committed
307 308 309 310 311
	QVector3D cameraPosition = rotateBack * (-m_translation);

	m_light.position.setX(cameraPosition.x());
	m_light.position.setY(cameraPosition.y());
	m_light.position.setZ(cameraPosition.z());
Anakin's avatar
Anakin committed
312 313
}

Anakin's avatar
Anakin committed
314 315

/////////////////////////////////////////////////////////////////////////
Anakin's avatar
Anakin committed
316
// private slots
Anakin's avatar
Anakin committed
317

Anakin's avatar
Anakin committed
318
void OglViewerWidget::resetView()
Anakin's avatar
Anakin committed
319
{
Anakin's avatar
Anakin committed
320 321
	m_rotation = QQuaternion();
	m_translation = { 0.0, 0.0, DEFAULT_Z_DISTANCE };
Anakin's avatar
Anakin committed
322
	m_zSpeed = 1;
Anakin's avatar
Anakin committed
323 324
	update();
}
Anakin's avatar
Anakin committed
325 326 327 328 329 330 331


/////////////////////////////////////////////////////////////////////////
// public slots

void OglViewerWidget::changeDirection(int direction)
{
Anakin's avatar
Anakin committed
332 333 334 335 336 337 338 339 340 341 342 343
	switch (direction)
	{
	case 1:
		m_rotDirections.x = !m_rotDirections.x;
		break;
	case 2:
		m_rotDirections.y = !m_rotDirections.y;
		break;
	case 3:
		m_rotDirections.z = !m_rotDirections.z;
		break;
	}
Anakin's avatar
Anakin committed
344
}
Anakin's avatar
Anakin committed
345 346 347 348 349 350

void OglViewerWidget::toggleWireframe()
{
	m_wireframe = 1 - m_wireframe;
	update();
}
Anakin's avatar
Anakin committed
351 352 353 354 355 356 357

void OglViewerWidget::toggleLight()
{
	m_lightOn = 1 - m_lightOn;

	if (m_lightOn)
	{
Anakin's avatar
Anakin committed
358
		m_backgroundColor = { m_light.intensities.x() / 50, m_light.intensities.y() / 50, m_light.intensities.z() / 50, 1.0 };
Anakin's avatar
Anakin committed
359 360 361 362 363

		updateLightPosition();
	}
	else
	{
364
		m_backgroundColor = { 0.5f, 0.8f, 1.0f, 1.0 };
Anakin's avatar
Anakin committed
365 366 367 368
	}

	update();
}
Anakin's avatar
Anakin committed
369 370 371 372 373

void OglViewerWidget::showSettings()
{
	m_settings->show();
}