reactphysics3d/examples/common/opengl-framework/src/GlutViewer.cpp

271 lines
9.2 KiB
C++

/********************************************************************************
* OpenGL-Framework *
* Copyright (c) 2013 Daniel Chappuis *
*********************************************************************************
* *
* This software is provided 'as-is', without any express or implied warranty. *
* In no event will the authors be held liable for any damages arising from the *
* use of this software. *
* *
* Permission is granted to anyone to use this software for any purpose, *
* including commercial applications, and to alter it and redistribute it *
* freely, subject to the following restrictions: *
* *
* 1. The origin of this software must not be misrepresented; you must not claim *
* that you wrote the original software. If you use this software in a *
* product, an acknowledgment in the product documentation would be *
* appreciated but is not required. *
* *
* 2. Altered source versions must be plainly marked as such, and must not be *
* misrepresented as being the original software. *
* *
* 3. This notice may not be removed or altered from any source distribution. *
* *
********************************************************************************/
// Libraries
#include "GlutViewer.h"
#include <string>
// Namespaces
using namespace openglframework;
using namespace std;
// Constructor
GlutViewer::GlutViewer() {
// Initialize the state of the mouse buttons
for (int i=0; i<10; i++) {
mIsButtonDown[i] = false;
}
}
// Destructor
GlutViewer::~GlutViewer() {
}
// Initialize the viewer
bool GlutViewer::init(int argc, char** argv, const string& windowsTitle,
const Vector2& windowsSize, const Vector2& windowsPosition,
bool isMultisamplingActive) {
// Initialize the GLUT library
bool outputValue = initGLUT(argc, argv, windowsTitle, windowsSize,
windowsPosition, isMultisamplingActive);
// Active the multi-sampling by default
if (isMultisamplingActive) {
activateMultiSampling(true);
}
return outputValue;
}
// Initialize the GLUT library
bool GlutViewer::initGLUT(int argc, char** argv, const string& windowsTitle,
const Vector2& windowsSize, const Vector2& windowsPosition,
bool isMultisamplingActive) {
// Initialize GLUT
glutInit(&argc, argv);
uint modeWithoutMultiSampling = GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH;
uint modeWithMultiSampling = GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GL_MULTISAMPLE;
uint displayMode = isMultisamplingActive ? modeWithMultiSampling : modeWithoutMultiSampling;
glutInitDisplayMode(displayMode);
// Initialize the size of the GLUT windows
glutInitWindowSize(static_cast<int>(windowsSize.x),
static_cast<int>(windowsSize.y));
// Initialize the position of the GLUT windows
glutInitWindowPosition(static_cast<int>(windowsPosition.x),
static_cast<int>(windowsPosition.y));
// Create the GLUT windows
glutCreateWindow(windowsTitle.c_str());
// Initialize the GLEW library
GLenum error = glewInit();
if (error != GLEW_OK) {
// Problem: glewInit failed, something is wrong
cerr << "GLEW Error : " << glewGetErrorString(error) << std::endl;
assert(false);
return false;
}
return true;
}
// Set the camera so that we can view the whole scene
void GlutViewer::resetCameraToViewAll() {
// Move the camera to the origin of the scene
mCamera.translateWorld(-mCamera.getOrigin());
// Move the camera to the center of the scene
mCamera.translateWorld(mCenterScene);
// Set the zoom of the camera so that the scene center is
// in negative view direction of the camera
mCamera.setZoom(1.0);
}
// Called when a GLUT mouse button event occurs
void GlutViewer::mouseButtonEvent(int button, int state, int x, int y) {
// If the mouse button is pressed
if (state == GLUT_DOWN) {
mLastMouseX = x;
mLastMouseY = y;
mIsLastPointOnSphereValid = mapMouseCoordinatesToSphere(x, y, mLastPointOnSphere);
mIsButtonDown[button] = true;
}
else { // If the mouse button is released
mIsLastPointOnSphereValid = false;
mIsButtonDown[button] = false;
// If it is a mouse wheel click event
if (button == 3) {
zoom(0, (int) (y - 0.05f * mCamera.getWidth()));
}
else if (button == 4) {
zoom(0, (int) (y + 0.05f * mCamera.getHeight()));
}
}
mModifiers = glutGetModifiers();
// Notify GLUT to redisplay
glutPostRedisplay();
}
// Called when a GLUT mouse motion event occurs
void GlutViewer::mouseMotionEvent(int xMouse, int yMouse) {
// Zoom
if ((mIsButtonDown[GLUT_LEFT_BUTTON] && mIsButtonDown[GLUT_MIDDLE_BUTTON]) ||
(mIsButtonDown[GLUT_LEFT_BUTTON] && mModifiers == GLUT_ACTIVE_ALT)) {
zoom(xMouse, yMouse);
}
// Translation
else if (mIsButtonDown[GLUT_MIDDLE_BUTTON] || mIsButtonDown[GLUT_RIGHT_BUTTON] ||
(mIsButtonDown[GLUT_LEFT_BUTTON] && (mModifiers == GLUT_ACTIVE_ALT))) {
translate(xMouse, yMouse);
}
// Rotation
else if (mIsButtonDown[GLUT_LEFT_BUTTON]) {
rotate(xMouse, yMouse);
}
// Remember the mouse position
mLastMouseX = xMouse;
mLastMouseY = yMouse;
mIsLastPointOnSphereValid = mapMouseCoordinatesToSphere(xMouse, yMouse, mLastPointOnSphere);
// Notify GLUT to redisplay
glutPostRedisplay();
}
// Called when a GLUT keyboard event occurs
void GlutViewer::keyboardEvent(int key, int xMouse, int yMouse) {
}
// Called when a GLUT special keyboard event occurs
void GlutViewer::keyboardSpecialEvent(int key, int xMouse, int yMouse) {
}
// Map the mouse x,y coordinates to a point on a sphere
bool GlutViewer::mapMouseCoordinatesToSphere(int xMouse, int yMouse, Vector3& spherePoint) const {
int width = mCamera.getWidth();
int height = mCamera.getHeight();
if ((xMouse >= 0) && (xMouse <= width) && (yMouse >= 0) && (yMouse <= height)) {
float x = float(xMouse - 0.5f * width) / float(width);
float y = float(0.5f * height - yMouse) / float(height);
float sinx = sin(PI * x * 0.5f);
float siny = sin(PI * y * 0.5f);
float sinx2siny2 = sinx * sinx + siny * siny;
// Compute the point on the sphere
spherePoint.x = sinx;
spherePoint.y = siny;
spherePoint.z = (sinx2siny2 < 1.0) ? sqrt(1.0f - sinx2siny2) : 0.0f;
return true;
}
return false;
}
// Zoom the camera
void GlutViewer::zoom(int xMouse, int yMouse) {
float dy = static_cast<float>(yMouse - mLastMouseY);
float h = static_cast<float>(mCamera.getHeight());
// Zoom the camera
mCamera.setZoom(-dy / h);
}
// Translate the camera
void GlutViewer::translate(int xMouse, int yMouse) {
float dx = static_cast<float>(xMouse - mLastMouseX);
float dy = static_cast<float>(yMouse - mLastMouseY);
// Translate the camera
mCamera.translateCamera(-dx / float(mCamera.getWidth()),
-dy / float(mCamera.getHeight()), mCenterScene);
}
// Rotate the camera
void GlutViewer::rotate(int xMouse, int yMouse) {
if (mIsLastPointOnSphereValid) {
Vector3 newPoint3D;
bool isNewPointOK = mapMouseCoordinatesToSphere(xMouse, yMouse, newPoint3D);
if (isNewPointOK) {
Vector3 axis = mLastPointOnSphere.cross(newPoint3D);
float cosAngle = mLastPointOnSphere.dot(newPoint3D);
float epsilon = std::numeric_limits<float>::epsilon();
if (fabs(cosAngle) < 1.0f && axis.length() > epsilon) {
axis.normalize();
float angle = 2.0f * acos(cosAngle);
// Rotate the camera around the center of the scene
mCamera.rotateAroundLocalPoint(axis, -angle, mCenterScene);
}
}
}
}
// Check the OpenGL errors
void GlutViewer::checkOpenGLErrors() {
GLenum glError;
// Get the OpenGL errors
glError = glGetError();
// While there are errors
while (glError != GL_NO_ERROR) {
// Get the error string
const GLubyte* stringError = gluErrorString(glError);
// Display the error
if (stringError)
cerr << "OpenGL Error #" << glError << "(" << gluErrorString(glError) << endl;
else
cerr << "OpenGL Error #" << glError << " (no message available)" << endl;
// Get the next error
glError = glGetError();
}
}