mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
Functional sixense "laser" oculus selection mode.
This commit is contained in:
parent
ba997334ff
commit
cc63f706a7
4 changed files with 215 additions and 66 deletions
|
@ -443,7 +443,15 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
|
||||||
ovrPosef pose = ss.Predicted.Pose;
|
ovrPosef pose = ss.Predicted.Pose;
|
||||||
Quatf orientation = Quatf(pose.Orientation);
|
Quatf orientation = Quatf(pose.Orientation);
|
||||||
orientation.GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
|
orientation.GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
|
||||||
|
} else {
|
||||||
|
yaw = 0.0f;
|
||||||
|
pitch = 0.0f;
|
||||||
|
roll = 0.0f;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
yaw = 0.0f;
|
||||||
|
pitch = 0.0f;
|
||||||
|
roll = 0.0f;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,7 +469,7 @@ QSize OculusManager::getRenderTargetSize() {
|
||||||
|
|
||||||
void OculusManager::renderLaserPointer() {
|
void OculusManager::renderLaserPointer() {
|
||||||
#ifdef HAVE_LIBOVR
|
#ifdef HAVE_LIBOVR
|
||||||
const float PALM_TIP_ROD_RADIUS = 0.009f;
|
const float PALM_TIP_ROD_RADIUS = 0.002f;
|
||||||
|
|
||||||
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
|
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
|
||||||
|
|
||||||
|
@ -482,8 +490,8 @@ void OculusManager::renderLaserPointer() {
|
||||||
|
|
||||||
glm::vec3 OculusManager::getLaserPointerTipPosition(const PalmData* palm) {
|
glm::vec3 OculusManager::getLaserPointerTipPosition(const PalmData* palm) {
|
||||||
#ifdef HAVE_LIBOVR
|
#ifdef HAVE_LIBOVR
|
||||||
const float PALM_TIP_ROD_LENGTH_MULT = 2.0f;
|
const float PALM_TIP_ROD_LENGTH_MULT = 11.0f;
|
||||||
return (palm->getTipPosition() - palm->getPosition()) * PALM_TIP_ROD_LENGTH_MULT;
|
return palm->getPosition() + (palm->getTipPosition() - palm->getPosition()) * PALM_TIP_ROD_LENGTH_MULT;
|
||||||
#endif
|
#endif
|
||||||
return glm::vec3(0.0f);
|
return glm::vec3(0.0f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "SixenseManager.h"
|
#include "SixenseManager.h"
|
||||||
|
#include "devices/OculusManager.h"
|
||||||
#include "UserActivityLogger.h"
|
#include "UserActivityLogger.h"
|
||||||
|
|
||||||
#ifdef HAVE_SIXENSE
|
#ifdef HAVE_SIXENSE
|
||||||
|
@ -358,9 +359,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||||
MyAvatar* avatar = application->getAvatar();
|
MyAvatar* avatar = application->getAvatar();
|
||||||
QGLWidget* widget = application->getGLWidget();
|
QGLWidget* widget = application->getGLWidget();
|
||||||
QPoint pos;
|
QPoint pos;
|
||||||
// Get directon relative to avatar orientation
|
|
||||||
glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection();
|
|
||||||
|
|
||||||
Qt::MouseButton bumperButton;
|
Qt::MouseButton bumperButton;
|
||||||
Qt::MouseButton triggerButton;
|
Qt::MouseButton triggerButton;
|
||||||
|
|
||||||
|
@ -372,15 +371,24 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||||
triggerButton = Qt::LeftButton;
|
triggerButton = Qt::LeftButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the angles, scaled between (-0.5,0.5)
|
if (OculusManager::isConnected()) {
|
||||||
float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
|
pos = application->getApplicationOverlay().getOculusPalmClickLocation(palm);
|
||||||
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
|
printf("CLICK: %d %d\n", pos.x(), pos.y());
|
||||||
|
} else {
|
||||||
|
// Get directon relative to avatar orientation
|
||||||
|
glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection();
|
||||||
|
|
||||||
// Get the pixel range over which the xAngle and yAngle are scaled
|
// Get the angles, scaled between (-0.5,0.5)
|
||||||
float cursorRange = widget->width() * getCursorPixelRangeMult();
|
float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
|
||||||
|
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
|
||||||
|
|
||||||
pos.setX(widget->width() / 2.0f + cursorRange * xAngle);
|
// Get the pixel range over which the xAngle and yAngle are scaled
|
||||||
pos.setY(widget->height() / 2.0f + cursorRange * yAngle);
|
float cursorRange = widget->width() * getCursorPixelRangeMult();
|
||||||
|
|
||||||
|
pos.setX(widget->width() / 2.0f + cursorRange * xAngle);
|
||||||
|
pos.setY(widget->height() / 2.0f + cursorRange * yAngle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//If we are off screen then we should stop processing, and if a trigger or bumper is pressed,
|
//If we are off screen then we should stop processing, and if a trigger or bumper is pressed,
|
||||||
//we should unpress them.
|
//we should unpress them.
|
||||||
|
|
|
@ -205,6 +205,103 @@ void ApplicationOverlay::getClickLocation(int &x, int &y) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should
|
||||||
|
//be multiplied by dir and added to origin to get the location of the collision
|
||||||
|
bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result)
|
||||||
|
{
|
||||||
|
//Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
|
||||||
|
|
||||||
|
//Compute A, B and C coefficients
|
||||||
|
float a = glm::dot(dir, dir);
|
||||||
|
float b = 2 * glm::dot(dir, origin);
|
||||||
|
float c = glm::dot(origin, origin) - (r * r);
|
||||||
|
|
||||||
|
//Find discriminant
|
||||||
|
float disc = b * b - 4 * a * c;
|
||||||
|
|
||||||
|
// if discriminant is negative there are no real roots, so return
|
||||||
|
// false as ray misses sphere
|
||||||
|
if (disc < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute q as described above
|
||||||
|
float distSqrt = sqrtf(disc);
|
||||||
|
float q;
|
||||||
|
if (b < 0) {
|
||||||
|
q = (-b - distSqrt) / 2.0;
|
||||||
|
} else {
|
||||||
|
q = (-b + distSqrt) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute t0 and t1
|
||||||
|
float t0 = q / a;
|
||||||
|
float t1 = c / q;
|
||||||
|
|
||||||
|
// make sure t0 is smaller than t1
|
||||||
|
if (t0 > t1) {
|
||||||
|
// if t0 is bigger than t1 swap them around
|
||||||
|
float temp = t0;
|
||||||
|
t0 = t1;
|
||||||
|
t1 = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if t1 is less than zero, the object is in the ray's negative direction
|
||||||
|
// and consequently the ray misses the sphere
|
||||||
|
if (t1 < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if t0 is less than zero, the intersection point is at t1
|
||||||
|
if (t0 < 0) {
|
||||||
|
*result = t1;
|
||||||
|
return true;
|
||||||
|
} else { // else the intersection point is at t0
|
||||||
|
*result = t0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPoint ApplicationOverlay::getOculusPalmClickLocation(PalmData *palm) const {
|
||||||
|
|
||||||
|
Application* application = Application::getInstance();
|
||||||
|
QGLWidget* glWidget = application->getGLWidget();
|
||||||
|
MyAvatar* myAvatar = application->getAvatar();
|
||||||
|
|
||||||
|
const int widgetWidth = glWidget->width();
|
||||||
|
const int widgetHeight = glWidget->height();
|
||||||
|
|
||||||
|
|
||||||
|
glm::vec3 tip = OculusManager::getLaserPointerTipPosition(palm);
|
||||||
|
glm::vec3 eyePos = myAvatar->getHead()->calculateAverageEyePosition();
|
||||||
|
glm::quat orientation = glm::inverse(myAvatar->getOrientation());
|
||||||
|
glm::vec3 dir = orientation * glm::normalize(eyePos - tip); //direction of ray goes towards camera
|
||||||
|
glm::vec3 tipPos = orientation * (tip - eyePos);
|
||||||
|
|
||||||
|
QPoint rv;
|
||||||
|
|
||||||
|
float t;
|
||||||
|
|
||||||
|
//Find intersection of crosshair ray
|
||||||
|
if (raySphereIntersect(dir, tipPos, 1, &t)){
|
||||||
|
glm::vec3 collisionPos = tipPos + dir * t;
|
||||||
|
|
||||||
|
float u = asin(collisionPos.x) / (_textureFov)+0.5f;
|
||||||
|
float v = 1.0 - (asin(collisionPos.y) / (_textureFov)+0.5f);
|
||||||
|
|
||||||
|
rv.setX(u * glWidget->width());
|
||||||
|
rv.setY(v * glWidget->height());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//if they did not click on the overlay, just set the coords to INT_MAX
|
||||||
|
rv.setX(INT_MAX);
|
||||||
|
rv.setY(INT_MAX);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
// Draws the FBO texture for Oculus rift.
|
// Draws the FBO texture for Oculus rift.
|
||||||
void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
||||||
|
|
||||||
|
@ -221,11 +318,14 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||||
glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture());
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
renderControllerPointersOculus();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture());
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
@ -277,8 +377,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
||||||
|
|
||||||
renderTexturedHemisphere();
|
renderTexturedHemisphere();
|
||||||
|
|
||||||
renderControllerPointersOculus();
|
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
|
@ -559,22 +657,6 @@ void ApplicationOverlay::renderControllerPointers() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findSphereIntersection(const glm::vec3 &start, const glm::vec3 &end, const glm::vec3 &spos, const float r, glm::vec3 &result) {
|
|
||||||
double a = pow(end.x - start.x, 2) + pow(end.y - start.y, 2) + pow(end.z - start.z, 2);
|
|
||||||
double b = 2.0f * ((end.x - start.x) * (start.x - spos.x) + (end.y - start.x) * (start.y - spos.y) + (end.z - start.z) * (start.z - spos.z));
|
|
||||||
double c = pow(start.x - spos.x, 2) + pow(start.y - spos.y, 2) + pow(start.z - spos.z, 2) - r*r;
|
|
||||||
|
|
||||||
double delta = b * b - 4.0 * a * c;
|
|
||||||
printf("Intersection Delta %lf\n", delta);
|
|
||||||
|
|
||||||
if (delta == 0) {
|
|
||||||
float d = -b / (2.0 * a);
|
|
||||||
result = start + d * (end - start);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplicationOverlay::renderControllerPointersOculus() {
|
void ApplicationOverlay::renderControllerPointersOculus() {
|
||||||
|
|
||||||
const bool useLaser = true;
|
const bool useLaser = true;
|
||||||
|
@ -589,54 +671,104 @@ void ApplicationOverlay::renderControllerPointersOculus() {
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
|
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
for (int i = 0; i < NUMBER_OF_MAGNIFIERS; i++) {
|
MyAvatar* myAvatar = application->getAvatar();
|
||||||
if (i > 0 && useLaser) {
|
|
||||||
MyAvatar* myAvatar = application->getAvatar();
|
//Determine how much we need to iterate
|
||||||
|
const int ITERATIONS = max(myAvatar->getHand()->getNumPalms(), 3);
|
||||||
|
|
||||||
|
for (int i = 0; i < ITERATIONS; i++) {
|
||||||
|
if (useLaser && i < myAvatar->getHand()->getNumPalms()) {
|
||||||
|
|
||||||
PalmData& palm = myAvatar->getHand()->getPalms()[i];
|
PalmData& palm = myAvatar->getHand()->getPalms()[i];
|
||||||
if (palm.isActive()) {
|
if (palm.isActive()) {
|
||||||
|
|
||||||
glm::vec3 tip = OculusManager::getLaserPointerTipPosition(&palm);
|
glm::vec3 tip = OculusManager::getLaserPointerTipPosition(&palm);
|
||||||
glm::vec3 result;
|
glm::vec3 result;
|
||||||
|
glm::vec3 eyePos = myAvatar->getHead()->calculateAverageEyePosition();
|
||||||
|
glm::quat orientation = glm::inverse(myAvatar->getOrientation());
|
||||||
|
glm::vec3 dir = orientation * glm::normalize(eyePos - tip); //direction of ray goes towards camera
|
||||||
|
glm::vec3 tipPos = (tip - eyePos);
|
||||||
|
|
||||||
|
float t;
|
||||||
|
float length = glm::length(eyePos - tip);
|
||||||
|
float size = 0.045f * length;
|
||||||
|
|
||||||
if (findSphereIntersection(myAvatar->getHead()->calculateAverageEyePosition(),
|
glm::vec3 up = glm::vec3(0.0, 1.0, 0.0) * size;
|
||||||
tip, glm::vec3(0, 0, 0), 1, result)){
|
glm::vec3 right = glm::vec3(1.0, 0.0, 0.0) * size;
|
||||||
printf("Intersection Found: ");
|
|
||||||
printVector(result);
|
glm::vec3 cursorVerts[4];
|
||||||
|
cursorVerts[0] = -right + up;
|
||||||
|
cursorVerts[1] = right + up;
|
||||||
|
cursorVerts[2] = right - up;
|
||||||
|
cursorVerts[3] = -right - up;
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
// glLoadIdentity();
|
||||||
|
|
||||||
|
// objToCamProj is the vector in world coordinates from the
|
||||||
|
// local origin to the camera projected in the XZ plane
|
||||||
|
glm::vec3 cursorToCameraXZ(-tipPos.x, 0, -tipPos.z);
|
||||||
|
cursorToCameraXZ = glm::normalize(cursorToCameraXZ);
|
||||||
|
|
||||||
|
// This is the original lookAt vector for the object
|
||||||
|
// in world coordinates
|
||||||
|
glm::vec3 direction(0, 0, 1);
|
||||||
|
glTranslatef(tip.x, tip.y, tip.z);
|
||||||
|
|
||||||
|
// easy fix to determine wether the angle is negative or positive
|
||||||
|
// for positive angles upAux will be a vector pointing in the
|
||||||
|
// positive y direction, otherwise upAux will point downwards
|
||||||
|
// effectively reversing the rotation.
|
||||||
|
glm::vec3 upAux = glm::cross(direction, cursorToCameraXZ);
|
||||||
|
|
||||||
|
// compute the angle
|
||||||
|
float angleCosine = glm::dot(direction, cursorToCameraXZ);
|
||||||
|
|
||||||
|
// perform the rotation. The if statement is used for stability reasons
|
||||||
|
// if the lookAt and objToCamProj vectors are too close together then
|
||||||
|
// |angleCosine| could be bigger than 1 due to lack of precision
|
||||||
|
if ((angleCosine < 0.999999) && (angleCosine > -0.999999)) {
|
||||||
|
glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, upAux[0], upAux[1], upAux[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// so far it is just like the cylindrical billboard. The code for the
|
||||||
|
// second rotation comes now
|
||||||
|
// The second part tilts the object so that it faces the camera
|
||||||
|
|
||||||
//float lX = sin((newULeft - 0.5f) * _textureFov);
|
// objToCam is the vector in world coordinates from
|
||||||
//float rX = sin((newURight - 0.5f) * _textureFov);
|
// the local origin to the camera
|
||||||
//float bY = sin((newVBottom - 0.5f) * _textureFov);
|
glm::vec3 cursorToCamera = glm::normalize(-tipPos);
|
||||||
//float tY = sin((newVTop - 0.5f) * _textureFov);
|
|
||||||
|
|
||||||
//float dist;
|
// Compute the angle between objToCamProj and objToCam,
|
||||||
////Bottom Left
|
//i.e. compute the required angle for the lookup vector
|
||||||
//dist = sqrt(lX * lX + bY * bY);
|
|
||||||
//float blZ = sqrt(1.0f - dist * dist);
|
|
||||||
////Top Left
|
|
||||||
//dist = sqrt(lX * lX + tY * tY);
|
|
||||||
//float tlZ = sqrt(1.0f - dist * dist);
|
|
||||||
////Bottom Right
|
|
||||||
//dist = sqrt(rX * rX + bY * bY);
|
|
||||||
//float brZ = sqrt(1.0f - dist * dist);
|
|
||||||
////Top Right
|
|
||||||
//dist = sqrt(rX * rX + tY * tY);
|
|
||||||
//float trZ = sqrt(1.0f - dist * dist);
|
|
||||||
|
|
||||||
//glBegin(GL_QUADS);
|
angleCosine = glm::dot(cursorToCameraXZ, cursorToCamera);
|
||||||
|
|
||||||
//glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], _alpha);
|
// Tilt the object. The test is done to prevent instability
|
||||||
|
// when objToCam and objToCamProj have a very small
|
||||||
|
// angle between them
|
||||||
|
|
||||||
//glTexCoord2f(0.0f, 0.0f); glVertex3f(lX, tY, -tlZ);
|
if ((angleCosine < 0.99990) && (angleCosine > -0.9999))
|
||||||
//glTexCoord2f(1.0f, 0.0f); glVertex3f(rX, tY, -trZ);
|
if (cursorToCamera.y < 0) {
|
||||||
//glTexCoord2f(1.0f, 1.0f); glVertex3f(rX, bY, -brZ);
|
glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, 1, 0, 0);
|
||||||
//glTexCoord2f(0.0f, 1.0f); glVertex3f(lX, bY, -blZ);
|
} else {
|
||||||
|
glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, -1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
//glEnd();
|
glBegin(GL_QUADS);
|
||||||
|
|
||||||
|
glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], _alpha);
|
||||||
|
|
||||||
|
glTexCoord2f(0.0f, 0.0f); glVertex3f(cursorVerts[0].x, cursorVerts[0].y, cursorVerts[0].z);
|
||||||
|
glTexCoord2f(1.0f, 0.0f); glVertex3f(cursorVerts[1].x, cursorVerts[1].y, cursorVerts[1].z);
|
||||||
|
glTexCoord2f(1.0f, 1.0f); glVertex3f(cursorVerts[2].x, cursorVerts[2].y, cursorVerts[2].z);
|
||||||
|
glTexCoord2f(0.0f, 1.0f); glVertex3f(cursorVerts[3].x, cursorVerts[3].y, cursorVerts[3].z);
|
||||||
|
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
} else {
|
} else if (i < NUMBER_OF_MAGNIFIERS) {
|
||||||
//Dont render the reticle if its inactive
|
//Dont render the reticle if its inactive
|
||||||
if (!_reticleActive[i]) {
|
if (!_reticleActive[i]) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -32,6 +32,7 @@ public:
|
||||||
void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov);
|
void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov);
|
||||||
void computeOculusPickRay(float x, float y, glm::vec3& direction) const;
|
void computeOculusPickRay(float x, float y, glm::vec3& direction) const;
|
||||||
void getClickLocation(int &x, int &y) const;
|
void getClickLocation(int &x, int &y) const;
|
||||||
|
QPoint getOculusPalmClickLocation(PalmData *palm) const;
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
QOpenGLFramebufferObject* getFramebufferObject();
|
QOpenGLFramebufferObject* getFramebufferObject();
|
||||||
|
|
Loading…
Reference in a new issue