mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 06:44:06 +02:00
pull from upstream
This commit is contained in:
commit
fe06ce2931
41 changed files with 824 additions and 636 deletions
|
@ -817,7 +817,12 @@ void Application::initializeUi() {
|
|||
|
||||
void Application::paintGL() {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
_glWidget->makeCurrent();
|
||||
PerformanceTimer perfTimer("paintGL");
|
||||
//Need accurate frame timing for the oculus rift
|
||||
if (OculusManager::isConnected()) {
|
||||
OculusManager::beginFrameTiming();
|
||||
}
|
||||
|
||||
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
|
@ -880,12 +885,10 @@ void Application::paintGL() {
|
|||
if (OculusManager::isConnected()) {
|
||||
//When in mirror mode, use camera rotation. Otherwise, use body rotation
|
||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
OculusManager::display(_myCamera.getRotation(), _myCamera.getPosition(), _myCamera);
|
||||
OculusManager::display(_glWidget, _myCamera.getRotation(), _myCamera.getPosition(), _myCamera);
|
||||
} else {
|
||||
OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getDefaultEyePosition(), _myCamera);
|
||||
OculusManager::display(_glWidget, _myAvatar->getWorldAlignedOrientation(), _myAvatar->getDefaultEyePosition(), _myCamera);
|
||||
}
|
||||
_myCamera.update(1.0f / _fps);
|
||||
|
||||
} else if (TV3DManager::isConnected()) {
|
||||
|
||||
TV3DManager::display(_myCamera);
|
||||
|
@ -904,8 +907,7 @@ void Application::paintGL() {
|
|||
glPopMatrix();
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
_rearMirrorTools->render(true);
|
||||
|
||||
_rearMirrorTools->render(true, _glWidget->mapFromGlobal(QCursor::pos()));
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
renderRearViewMirror(_mirrorViewRect);
|
||||
}
|
||||
|
@ -919,6 +921,13 @@ void Application::paintGL() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!OculusManager::isConnected() || OculusManager::allowSwap()) {
|
||||
_glWidget->swapBuffers();
|
||||
}
|
||||
|
||||
if (OculusManager::isConnected()) {
|
||||
OculusManager::endFrameTiming();
|
||||
}
|
||||
_frameCount++;
|
||||
}
|
||||
|
||||
|
@ -960,6 +969,7 @@ void Application::resetCamerasOnResizeGL(Camera& camera, int width, int height)
|
|||
}
|
||||
|
||||
void Application::resizeGL(int width, int height) {
|
||||
DependencyManager::get<TextureCache>()->setFrameBufferSize(QSize(width, height));
|
||||
resetCamerasOnResizeGL(_myCamera, width, height);
|
||||
|
||||
glViewport(0, 0, width, height); // shouldn't this account for the menu???
|
||||
|
@ -1310,8 +1320,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
if (!event->isAutoRepeat()) {
|
||||
// this starts an HFActionEvent
|
||||
HFActionEvent startActionEvent(HFActionEvent::startType(),
|
||||
_myCamera.computePickRay(getTrueMouseX(),
|
||||
getTrueMouseY()));
|
||||
computePickRay(getTrueMouseX(), getTrueMouseY()));
|
||||
sendEvent(this, &startActionEvent);
|
||||
}
|
||||
|
||||
|
@ -1366,8 +1375,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
|
|||
if (!event->isAutoRepeat()) {
|
||||
// this ends the HFActionEvent
|
||||
HFActionEvent endActionEvent(HFActionEvent::endType(),
|
||||
_myCamera.computePickRay(getTrueMouseX(),
|
||||
getTrueMouseY()));
|
||||
computePickRay(getTrueMouseX(), getTrueMouseY()));
|
||||
sendEvent(this, &endActionEvent);
|
||||
}
|
||||
break;
|
||||
|
@ -1475,7 +1483,7 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
|
||||
// nobody handled this - make it an action event on the _window object
|
||||
HFActionEvent actionEvent(HFActionEvent::startType(),
|
||||
_myCamera.computePickRay(event->x(), event->y()));
|
||||
computePickRay(event->x(), event->y()));
|
||||
sendEvent(this, &actionEvent);
|
||||
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
|
@ -1530,7 +1538,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
|
||||
// fire an action end event
|
||||
HFActionEvent actionEvent(HFActionEvent::endType(),
|
||||
_myCamera.computePickRay(event->x(), event->y()));
|
||||
computePickRay(event->x(), event->y()));
|
||||
sendEvent(this, &actionEvent);
|
||||
}
|
||||
}
|
||||
|
@ -2137,19 +2145,16 @@ void Application::init() {
|
|||
_entityClipboardRenderer.setViewFrustum(getViewFrustum());
|
||||
_entityClipboardRenderer.setTree(&_entityClipboard);
|
||||
|
||||
_rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect);
|
||||
_rearMirrorTools = new RearMirrorTools(_mirrorViewRect);
|
||||
|
||||
connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
|
||||
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
|
||||
connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
|
||||
connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
|
||||
|
||||
// make sure our texture cache knows about window size changes
|
||||
DependencyManager::get<TextureCache>()->associateWithWidget(_glWidget);
|
||||
|
||||
// initialize the GlowEffect with our widget
|
||||
DependencyManager::get<GlowEffect>()->init(_glWidget,
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect));
|
||||
bool glow = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect);
|
||||
DependencyManager::get<GlowEffect>()->init(glow);
|
||||
}
|
||||
|
||||
void Application::closeMirrorView() {
|
||||
|
@ -2200,7 +2205,7 @@ void Application::updateMouseRay() {
|
|||
// make sure the frustum is up-to-date
|
||||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
|
||||
PickRay pickRay = _myCamera.computePickRay(getTrueMouseX(), getTrueMouseY());
|
||||
PickRay pickRay = computePickRay(getTrueMouseX(), getTrueMouseY());
|
||||
_mouseRayOrigin = pickRay.origin;
|
||||
_mouseRayDirection = pickRay.direction;
|
||||
|
||||
|
@ -3028,8 +3033,17 @@ int Application::getBoundaryLevelAdjust() const {
|
|||
return DependencyManager::get<LODManager>()->getBoundaryLevelAdjust();
|
||||
}
|
||||
|
||||
PickRay Application::computePickRay(float x, float y) {
|
||||
return getCamera()->computePickRay(x, y);
|
||||
PickRay Application::computePickRay(float x, float y) const {
|
||||
glm::vec2 size = getCanvasSize();
|
||||
x /= size.x;
|
||||
y /= size.y;
|
||||
PickRay result;
|
||||
if (isHMDMode()) {
|
||||
ApplicationOverlay::computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
|
||||
} else {
|
||||
getViewFrustum()->computePickRay(x, y, result.origin, result.direction);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QImage Application::renderAvatarBillboard() {
|
||||
|
@ -3062,6 +3076,16 @@ ViewFrustum* Application::getViewFrustum() {
|
|||
return &_viewFrustum;
|
||||
}
|
||||
|
||||
const ViewFrustum* Application::getViewFrustum() const {
|
||||
#ifdef DEBUG
|
||||
if (QThread::currentThread() == activeRenderingThread) {
|
||||
// FIXME, should this be an assert?
|
||||
qWarning() << "Calling Application::getViewFrustum() from the active rendering thread, did you mean Application::getDisplayViewFrustum()?";
|
||||
}
|
||||
#endif
|
||||
return &_viewFrustum;
|
||||
}
|
||||
|
||||
ViewFrustum* Application::getDisplayViewFrustum() {
|
||||
#ifdef DEBUG
|
||||
if (QThread::currentThread() != activeRenderingThread) {
|
||||
|
@ -3434,7 +3458,6 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
|
|||
_mirrorCamera.setAspectRatio((float)region.width() / region.height());
|
||||
|
||||
_mirrorCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f)));
|
||||
_mirrorCamera.update(1.0f/_fps);
|
||||
|
||||
// set the bounds of rear mirror view
|
||||
if (billboard) {
|
||||
|
@ -3460,7 +3483,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
|
|||
glPopMatrix();
|
||||
|
||||
if (!billboard) {
|
||||
_rearMirrorTools->render(false);
|
||||
_rearMirrorTools->render(false, _glWidget->mapFromGlobal(QCursor::pos()));
|
||||
}
|
||||
|
||||
// reset Viewport and projection matrix
|
||||
|
@ -4344,7 +4367,7 @@ void Application::takeSnapshot() {
|
|||
player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
|
||||
player->play();
|
||||
|
||||
QString fileName = Snapshot::saveSnapshot();
|
||||
QString fileName = Snapshot::saveSnapshot(_glWidget->grabFrameBuffer());
|
||||
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
if (!accountManager.isLoggedIn()) {
|
||||
|
@ -4533,3 +4556,51 @@ void Application::postLambdaEvent(std::function<void()> f) {
|
|||
QCoreApplication::postEvent(this, new LambdaEvent(f));
|
||||
}
|
||||
|
||||
void Application::initPlugins() {
|
||||
OculusManager::init();
|
||||
}
|
||||
|
||||
void Application::shutdownPlugins() {
|
||||
OculusManager::deinit();
|
||||
}
|
||||
|
||||
glm::vec3 Application::getHeadPosition() const {
|
||||
return OculusManager::getRelativePosition();
|
||||
}
|
||||
|
||||
|
||||
glm::quat Application::getHeadOrientation() const {
|
||||
return OculusManager::getOrientation();
|
||||
}
|
||||
|
||||
glm::uvec2 Application::getCanvasSize() const {
|
||||
return glm::uvec2(_glWidget->width(), _glWidget->height());
|
||||
}
|
||||
|
||||
QSize Application::getDeviceSize() const {
|
||||
return _glWidget->getDeviceSize();
|
||||
}
|
||||
|
||||
int Application::getTrueMouseX() const {
|
||||
return _glWidget->mapFromGlobal(QCursor::pos()).x();
|
||||
}
|
||||
|
||||
int Application::getTrueMouseY() const {
|
||||
return _glWidget->mapFromGlobal(QCursor::pos()).y();
|
||||
}
|
||||
|
||||
bool Application::isThrottleRendering() const {
|
||||
return _glWidget->isThrottleRendering();
|
||||
}
|
||||
|
||||
PickRay Application::computePickRay() const {
|
||||
return computePickRay(getTrueMouseX(), getTrueMouseY());
|
||||
}
|
||||
|
||||
bool Application::hasFocus() const {
|
||||
return _glWidget->hasFocus();
|
||||
}
|
||||
|
||||
void Application::resizeGL() {
|
||||
this->resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
}
|
||||
|
|
|
@ -148,6 +148,8 @@ public:
|
|||
static glm::quat getOrientationForPath() { return getInstance()->_myAvatar->getOrientation(); }
|
||||
static glm::vec3 getPositionForAudio() { return getInstance()->_myAvatar->getHead()->getPosition(); }
|
||||
static glm::quat getOrientationForAudio() { return getInstance()->_myAvatar->getHead()->getFinalOrientationInWorldFrame(); }
|
||||
static void initPlugins();
|
||||
static void shutdownPlugins();
|
||||
|
||||
Application(int& argc, char** argv, QElapsedTimer &startup_time);
|
||||
~Application();
|
||||
|
@ -163,6 +165,8 @@ public:
|
|||
void paintGL();
|
||||
void resizeGL(int width, int height);
|
||||
|
||||
void resizeEvent(QResizeEvent * size);
|
||||
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
void keyReleaseEvent(QKeyEvent* event);
|
||||
|
||||
|
@ -185,12 +189,19 @@ public:
|
|||
bool event(QEvent* event);
|
||||
bool eventFilter(QObject* object, QEvent* event);
|
||||
|
||||
GLCanvas* getGLWidget() { return _glWidget; }
|
||||
bool isThrottleRendering() const { return _glWidget->isThrottleRendering(); }
|
||||
glm::uvec2 getCanvasSize() const;
|
||||
QSize getDeviceSize() const;
|
||||
bool hasFocus() const;
|
||||
PickRay computePickRay() const;
|
||||
PickRay computeViewPickRay(float xRatio, float yRatio) const;
|
||||
void resizeGL();
|
||||
|
||||
bool isThrottleRendering() const;
|
||||
|
||||
Camera* getCamera() { return &_myCamera; }
|
||||
// Represents the current view frustum of the avatar.
|
||||
ViewFrustum* getViewFrustum();
|
||||
const ViewFrustum* getViewFrustum() const;
|
||||
// Represents the view frustum of the current rendering pass,
|
||||
// which might be different from the viewFrustum, i.e. shadowmap
|
||||
// passes, mirror window passes, etc
|
||||
|
@ -212,8 +223,9 @@ public:
|
|||
bool mouseOnScreen() const;
|
||||
int getMouseX() const;
|
||||
int getMouseY() const;
|
||||
int getTrueMouseX() const { return _glWidget->mapFromGlobal(QCursor::pos()).x(); }
|
||||
int getTrueMouseY() const { return _glWidget->mapFromGlobal(QCursor::pos()).y(); }
|
||||
glm::ivec2 getTrueMousePosition() const;
|
||||
int getTrueMouseX() const;
|
||||
int getTrueMouseY() const;
|
||||
int getMouseDragStartedX() const;
|
||||
int getMouseDragStartedY() const;
|
||||
int getTrueMouseDragStartedX() const { return _mouseDragStartedX; }
|
||||
|
@ -225,6 +237,7 @@ public:
|
|||
|
||||
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
||||
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
|
||||
const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; }
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
|
||||
float getFps() const { return _fps; }
|
||||
|
@ -284,7 +297,7 @@ public:
|
|||
virtual QThread* getMainThread() { return thread(); }
|
||||
virtual float getSizeScale() const;
|
||||
virtual int getBoundaryLevelAdjust() const;
|
||||
virtual PickRay computePickRay(float x, float y);
|
||||
virtual PickRay computePickRay(float x, float y) const;
|
||||
virtual const glm::vec3& getAvatarPosition() const { return _myAvatar->getPosition(); }
|
||||
virtual void overrideEnvironmentData(const EnvironmentData& newData) { _environment.override(newData); }
|
||||
virtual void endOverrideEnvironmentData() { _environment.endOverride(); }
|
||||
|
@ -294,8 +307,8 @@ public:
|
|||
|
||||
FileLogger* getLogger() { return _logger; }
|
||||
|
||||
glm::vec2 getViewportDimensions() const { return glm::vec2(_glWidget->getDeviceWidth(),
|
||||
_glWidget->getDeviceHeight()); }
|
||||
glm::vec2 getViewportDimensions() const;
|
||||
|
||||
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
|
||||
|
||||
void skipVersion(QString latestVersion);
|
||||
|
@ -317,7 +330,9 @@ public:
|
|||
// rendering of several elements depend on that
|
||||
// TODO: carry that information on the Camera as a setting
|
||||
bool isHMDMode() const;
|
||||
|
||||
glm::quat getHeadOrientation() const;
|
||||
glm::vec3 getHeadPosition() const;
|
||||
|
||||
QRect getDesirableApplicationGeometry();
|
||||
RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; }
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "Camera.h"
|
||||
#include "Menu.h"
|
||||
#include "Util.h"
|
||||
#include "devices/OculusManager.h"
|
||||
|
||||
|
||||
CameraMode stringToMode(const QString& mode) {
|
||||
|
@ -121,18 +120,7 @@ void Camera::setFarClip(float f) {
|
|||
}
|
||||
|
||||
PickRay Camera::computePickRay(float x, float y) {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
return computeViewPickRay(x / glCanvas->width(), y / glCanvas->height());
|
||||
}
|
||||
|
||||
PickRay Camera::computeViewPickRay(float xRatio, float yRatio) {
|
||||
PickRay result;
|
||||
if (OculusManager::isConnected()) {
|
||||
Application::getInstance()->getApplicationOverlay().computeOculusPickRay(xRatio, yRatio, result.origin, result.direction);
|
||||
} else {
|
||||
Application::getInstance()->getViewFrustum()->computePickRay(xRatio, yRatio, result.origin, result.direction);
|
||||
}
|
||||
return result;
|
||||
return qApp->computePickRay(x, y);
|
||||
}
|
||||
|
||||
void Camera::setModeString(const QString& mode) {
|
||||
|
|
|
@ -77,7 +77,6 @@ public slots:
|
|||
glm::quat getOrientation() const { return getRotation(); }
|
||||
|
||||
PickRay computePickRay(float x, float y);
|
||||
PickRay computeViewPickRay(float xRatio, float yRatio);
|
||||
|
||||
// These only work on independent cameras
|
||||
/// one time change to what the camera is looking at
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "Application.h"
|
||||
#include "GLCanvas.h"
|
||||
#include "MainWindow.h"
|
||||
#include "devices/OculusManager.h"
|
||||
|
||||
const int MSECS_PER_FRAME_WHEN_THROTTLED = 66;
|
||||
|
||||
|
@ -60,21 +59,7 @@ void GLCanvas::initializeGL() {
|
|||
|
||||
void GLCanvas::paintGL() {
|
||||
if (!_throttleRendering && !Application::getInstance()->getWindow()->isMinimized()) {
|
||||
//Need accurate frame timing for the oculus rift
|
||||
if (OculusManager::isConnected()) {
|
||||
OculusManager::beginFrameTiming();
|
||||
}
|
||||
|
||||
Application::getInstance()->paintGL();
|
||||
|
||||
if (!OculusManager::isConnected()) {
|
||||
swapBuffers();
|
||||
} else {
|
||||
if (OculusManager::allowSwap()) {
|
||||
swapBuffers();
|
||||
}
|
||||
OculusManager::endFrameTiming();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,18 +95,7 @@ void GLCanvas::activeChanged(Qt::ApplicationState state) {
|
|||
void GLCanvas::throttleRender() {
|
||||
_frameTimer.start(_idleRenderInterval);
|
||||
if (!Application::getInstance()->getWindow()->isMinimized()) {
|
||||
//Need accurate frame timing for the oculus rift
|
||||
if (OculusManager::isConnected()) {
|
||||
OculusManager::beginFrameTiming();
|
||||
}
|
||||
|
||||
makeCurrent();
|
||||
Application::getInstance()->paintGL();
|
||||
swapBuffers();
|
||||
|
||||
if (OculusManager::isConnected()) {
|
||||
OculusManager::endFrameTiming();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <GLCanvas.h>
|
||||
#include <PathUtils.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AudioToolBox.h"
|
||||
|
@ -38,15 +39,14 @@ bool AudioToolBox::mousePressEvent(int x, int y) {
|
|||
void AudioToolBox::render(int x, int y, int padding, bool boxed) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
if (_micTextureId == 0) {
|
||||
_micTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/mic.svg"));
|
||||
if (!_micTexture) {
|
||||
_micTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/mic.svg");
|
||||
}
|
||||
if (_muteTextureId == 0) {
|
||||
_muteTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/mic-mute.svg"));
|
||||
if (!_muteTexture) {
|
||||
_muteTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/mic-mute.svg");
|
||||
}
|
||||
if (_boxTextureId == 0) {
|
||||
_boxTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/audio-box.svg"));
|
||||
if (_boxTexture) {
|
||||
_boxTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/audio-box.svg");
|
||||
}
|
||||
|
||||
auto audioIO = DependencyManager::get<AudioClient>();
|
||||
|
@ -59,11 +59,8 @@ void AudioToolBox::render(int x, int y, int padding, bool boxed) {
|
|||
const int BOX_HEIGHT = 44;
|
||||
|
||||
QRect boxBounds = QRect(x - BOX_LEFT_PADDING, y - BOX_TOP_PADDING, BOX_WIDTH, BOX_HEIGHT);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _boxTextureId);
|
||||
|
||||
glm::vec4 quadColor;
|
||||
|
||||
|
||||
if (isClipping) {
|
||||
quadColor = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
} else {
|
||||
|
@ -71,9 +68,9 @@ void AudioToolBox::render(int x, int y, int padding, bool boxed) {
|
|||
}
|
||||
glm::vec2 topLeft(boxBounds.left(), boxBounds.top());
|
||||
glm::vec2 bottomRight(boxBounds.right(), boxBounds.bottom());
|
||||
glm::vec2 texCoordTopLeft(1,1);
|
||||
glm::vec2 texCoordBottomRight(0,0);
|
||||
|
||||
static const glm::vec2 texCoordTopLeft(1,1);
|
||||
static const glm::vec2 texCoordBottomRight(0, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_boxTexture));
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
|
||||
}
|
||||
|
||||
|
@ -81,10 +78,10 @@ void AudioToolBox::render(int x, int y, int padding, bool boxed) {
|
|||
|
||||
_iconBounds = QRect(x + padding, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE);
|
||||
if (!audioIO->isMuted()) {
|
||||
glBindTexture(GL_TEXTURE_2D, _micTextureId);
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_micTexture));
|
||||
iconColor = 1.0f;
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, _muteTextureId);
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_muteTexture));
|
||||
|
||||
// Make muted icon pulsate
|
||||
static const float PULSE_MIN = 0.4f;
|
||||
|
@ -112,6 +109,6 @@ void AudioToolBox::render(int x, int y, int padding, bool boxed) {
|
|||
}
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor, _boxQuadID);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <QOpenGLTexture>
|
||||
|
||||
class AudioToolBox : public Dependency {
|
||||
SINGLETON_DEPENDENCY
|
||||
|
@ -24,9 +25,9 @@ public:
|
|||
protected:
|
||||
AudioToolBox();
|
||||
private:
|
||||
GLuint _micTextureId = 0;
|
||||
GLuint _muteTextureId = 0;
|
||||
GLuint _boxTextureId = 0;
|
||||
gpu::TexturePointer _micTexture;
|
||||
gpu::TexturePointer _muteTexture;
|
||||
gpu::TexturePointer _boxTexture;
|
||||
int _boxQuadID = GeometryCache::UNKNOWN_ID;
|
||||
QRect _iconBounds;
|
||||
qint64 _iconPulseTimeReference = 0;
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "Recorder.h"
|
||||
#include "Util.h"
|
||||
#include "world.h"
|
||||
#include "devices/OculusManager.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
using namespace std;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "Util.h"
|
||||
#include "devices/DdeFaceTracker.h"
|
||||
#include "devices/Faceshift.h"
|
||||
#include "devices/OculusManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -309,7 +308,7 @@ glm::quat Head::getCameraOrientation() const {
|
|||
// to change the driving direction while in Oculus mode. It is used to support driving toward where you're
|
||||
// head is looking. Note that in oculus mode, your actual camera view and where your head is looking is not
|
||||
// always the same.
|
||||
if (OculusManager::isConnected()) {
|
||||
if (qApp->isHMDMode()) {
|
||||
return getOrientation();
|
||||
}
|
||||
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar);
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
#include "Physics.h"
|
||||
#include "Recorder.h"
|
||||
#include "devices/Faceshift.h"
|
||||
#include "devices/OculusManager.h"
|
||||
#include "Util.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
|
@ -230,12 +229,14 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
void MyAvatar::updateFromTrackers(float deltaTime) {
|
||||
glm::vec3 estimatedPosition, estimatedRotation;
|
||||
|
||||
if (isPlaying() && !OculusManager::isConnected()) {
|
||||
bool inHmd = qApp->isHMDMode();
|
||||
|
||||
if (isPlaying() && inHmd) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (OculusManager::isConnected()) {
|
||||
estimatedPosition = OculusManager::getRelativePosition();
|
||||
|
||||
if (inHmd) {
|
||||
estimatedPosition = qApp->getHeadPosition();
|
||||
estimatedPosition.x *= -1.0f;
|
||||
_trackedHeadPosition = estimatedPosition;
|
||||
|
||||
|
@ -273,7 +274,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
|||
|
||||
|
||||
Head* head = getHead();
|
||||
if (OculusManager::isConnected() || isPlaying()) {
|
||||
if (inHmd || isPlaying()) {
|
||||
head->setDeltaPitch(estimatedRotation.x);
|
||||
head->setDeltaYaw(estimatedRotation.y);
|
||||
} else {
|
||||
|
@ -293,7 +294,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
|||
// NOTE: this is kinda a hack, it's the same hack we use to make the head tilt. But it's not really a mirror
|
||||
// it just makes you feel like you're looking in a mirror because the body movements of the avatar appear to
|
||||
// match your body movements.
|
||||
if (OculusManager::isConnected() && Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
|
||||
if (inHmd && Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
|
||||
relativePosition.x = -relativePosition.x;
|
||||
}
|
||||
|
||||
|
@ -882,8 +883,10 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
|||
howManyLookingAtMe++;
|
||||
// Have that avatar look directly at my camera
|
||||
// Philip TODO: correct to look at left/right eye
|
||||
if (OculusManager::isConnected()) {
|
||||
avatar->getHead()->setCorrectedLookAtPosition(OculusManager::getLeftEyePosition());
|
||||
if (qApp->isHMDMode()) {
|
||||
avatar->getHead()->setCorrectedLookAtPosition(Application::getInstance()->getViewFrustum()->getPosition());
|
||||
// FIXME what is the point of this?
|
||||
// avatar->getHead()->setCorrectedLookAtPosition(OculusManager::getLeftEyePosition());
|
||||
} else {
|
||||
avatar->getHead()->setCorrectedLookAtPosition(Application::getInstance()->getViewFrustum()->getPosition());
|
||||
}
|
||||
|
@ -1213,7 +1216,7 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
// Gather rotation information from keyboard
|
||||
const float TIME_BETWEEN_HMD_TURNS = 0.5f;
|
||||
const float HMD_TURN_DEGREES = 22.5f;
|
||||
if (!OculusManager::isConnected()) {
|
||||
if (!qApp->isHMDMode()) {
|
||||
// Smoothly rotate body with arrow keys if not in HMD
|
||||
_bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime;
|
||||
_bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_SPEED * deltaTime;
|
||||
|
@ -1247,29 +1250,23 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
float MINIMUM_ROTATION_RATE = 2.0f;
|
||||
if (fabs(_bodyYawDelta) < MINIMUM_ROTATION_RATE) { _bodyYawDelta = 0.0f; }
|
||||
|
||||
if (OculusManager::isConnected()) {
|
||||
if (qApp->isHMDMode()) {
|
||||
// these angles will be in radians
|
||||
float yaw, pitch, roll;
|
||||
OculusManager::getEulerAngles(yaw, pitch, roll);
|
||||
glm::quat orientation = qApp->getHeadOrientation();
|
||||
// ... so they need to be converted to degrees before we do math...
|
||||
yaw *= DEGREES_PER_RADIAN;
|
||||
pitch *= DEGREES_PER_RADIAN;
|
||||
roll *= DEGREES_PER_RADIAN;
|
||||
|
||||
glm::vec3 euler = glm::eulerAngles(orientation) * DEGREES_PER_RADIAN;
|
||||
|
||||
//Invert yaw and roll when in mirror mode
|
||||
Head* head = getHead();
|
||||
if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
|
||||
head->setBaseYaw(-yaw);
|
||||
head->setBasePitch(pitch);
|
||||
head->setBaseRoll(-roll);
|
||||
} else {
|
||||
head->setBaseYaw(yaw);
|
||||
head->setBasePitch(pitch);
|
||||
head->setBaseRoll(roll);
|
||||
YAW(euler) *= -1.0;
|
||||
ROLL(euler) *= -1.0;
|
||||
}
|
||||
|
||||
Head* head = getHead();
|
||||
head->setBaseYaw(YAW(euler));
|
||||
head->setBasePitch(PITCH(euler));
|
||||
head->setBaseRoll(ROLL(euler));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVelocity, bool isHovering) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <GLCanvas.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "gpu/GLBackend.h"
|
||||
#include "Application.h"
|
||||
#include "CameraToolBox.h"
|
||||
#include "FaceTracker.h"
|
||||
|
@ -74,21 +75,20 @@ void CameraToolBox::toggleMute() {
|
|||
void CameraToolBox::render(int x, int y, bool boxed) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
if (_enabledTextureId == 0) {
|
||||
_enabledTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/face.svg"));
|
||||
if (!_enabledTexture) {
|
||||
_enabledTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/face.svg");
|
||||
}
|
||||
if (_mutedTextureId == 0) {
|
||||
_mutedTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/face-mute.svg"));
|
||||
if (!_mutedTexture) {
|
||||
_mutedTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/face-mute.svg");
|
||||
}
|
||||
|
||||
const int MUTE_ICON_SIZE = 24;
|
||||
_iconBounds = QRect(x, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE);
|
||||
float iconColor = 1.0f;
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)) {
|
||||
glBindTexture(GL_TEXTURE_2D, _enabledTextureId);
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_enabledTexture));
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, _mutedTextureId);
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_mutedTexture));
|
||||
|
||||
// Make muted icon pulsate
|
||||
static const float PULSE_MIN = 0.4f;
|
||||
|
|
|
@ -34,8 +34,8 @@ private slots:
|
|||
void toggleMute();
|
||||
|
||||
private:
|
||||
GLuint _enabledTextureId = 0;
|
||||
GLuint _mutedTextureId = 0;
|
||||
gpu::TexturePointer _enabledTexture;
|
||||
gpu::TexturePointer _mutedTexture;
|
||||
int _boxQuadID = GeometryCache::UNKNOWN_ID;
|
||||
QRect _iconBounds;
|
||||
qint64 _iconPulseTimeReference = 0;
|
||||
|
|
|
@ -455,8 +455,7 @@ void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenH
|
|||
}
|
||||
|
||||
//Displays everything for the oculus, frame timing must be active
|
||||
void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) {
|
||||
|
||||
#ifdef DEBUG
|
||||
// Ensure the frame counter always increments by exactly 1
|
||||
|
@ -617,7 +616,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
_camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].HmdToEyeViewOffset.x, -_eyeRenderDesc[eye].HmdToEyeViewOffset.y, -_eyeRenderDesc[eye].HmdToEyeViewOffset.z));
|
||||
Application::getInstance()->displaySide(*_camera, false, RenderArgs::MONO);
|
||||
|
||||
applicationOverlay.displayOverlayTextureOculus(*_camera);
|
||||
applicationOverlay.displayOverlayTextureHmd(*_camera);
|
||||
});
|
||||
_activeEye = ovrEye_Count;
|
||||
|
||||
|
@ -638,7 +637,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
glPopMatrix();
|
||||
|
||||
// restore our normal viewport
|
||||
glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
auto deviceSize = qApp->getDeviceSize();
|
||||
glViewport(0, 0, deviceSize.width(), deviceSize.height());
|
||||
|
||||
#if 0
|
||||
if (debugFrame && !timerActive) {
|
||||
|
@ -707,8 +707,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) {
|
||||
|
||||
glLoadIdentity();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
glOrtho(0, glCanvas->getDeviceWidth(), 0, glCanvas->getDeviceHeight(), -1.0, 1.0);
|
||||
auto deviceSize = qApp->getDeviceSize();
|
||||
glOrtho(0, deviceSize.width(), 0, deviceSize.height(), -1.0, 1.0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
|
@ -794,8 +794,12 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
|
|||
|
||||
glm::vec3 OculusManager::getRelativePosition() {
|
||||
ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
|
||||
ovrVector3f headPosition = trackingState.HeadPose.ThePose.Position;
|
||||
return glm::vec3(headPosition.x, headPosition.y, headPosition.z);
|
||||
return toGlm(trackingState.HeadPose.ThePose.Position);
|
||||
}
|
||||
|
||||
glm::quat OculusManager::getOrientation() {
|
||||
ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
|
||||
return toGlm(trackingState.HeadPose.ThePose.Orientation);
|
||||
}
|
||||
|
||||
//Used to set the size of the glow framebuffers
|
||||
|
|
|
@ -61,7 +61,7 @@ public:
|
|||
static void endFrameTiming();
|
||||
static bool allowSwap();
|
||||
static void configureCamera(Camera& camera, int screenWidth, int screenHeight);
|
||||
static void display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera);
|
||||
static void display(QGLWidget * glCanvas, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera);
|
||||
static void reset();
|
||||
|
||||
/// param \yaw[out] yaw in radians
|
||||
|
@ -69,6 +69,7 @@ public:
|
|||
/// param \roll[out] roll in radians
|
||||
static void getEulerAngles(float& yaw, float& pitch, float& roll);
|
||||
static glm::vec3 getRelativePosition();
|
||||
static glm::quat getOrientation();
|
||||
static QSize getRenderTargetSize();
|
||||
|
||||
static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include "Application.h"
|
||||
#include "SixenseManager.h"
|
||||
#include "devices/OculusManager.h"
|
||||
#include "UserActivityLogger.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
|
@ -473,7 +472,6 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers)
|
|||
//Injecting mouse movements and clicks
|
||||
void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
QPoint pos;
|
||||
|
||||
Qt::MouseButton bumperButton;
|
||||
|
@ -499,12 +497,12 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
|||
// Get the angles, scaled between (-0.5,0.5)
|
||||
float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
|
||||
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
|
||||
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
// Get the pixel range over which the xAngle and yAngle are scaled
|
||||
float cursorRange = glCanvas->width() * getCursorPixelRangeMult();
|
||||
float cursorRange = canvasSize.x * getCursorPixelRangeMult();
|
||||
|
||||
pos.setX(glCanvas->width() / 2.0f + cursorRange * xAngle);
|
||||
pos.setY(glCanvas->height() / 2.0f + cursorRange * yAngle);
|
||||
pos.setX(canvasSize.x / 2.0f + cursorRange * xAngle);
|
||||
pos.setY(canvasSize.y / 2.0f + cursorRange * yAngle);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -33,12 +33,8 @@ bool TV3DManager::isConnected() {
|
|||
}
|
||||
|
||||
void TV3DManager::connect() {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
int width = glCanvas->getDeviceWidth();
|
||||
int height = glCanvas->getDeviceHeight();
|
||||
Camera& camera = *Application::getInstance()->getCamera();
|
||||
|
||||
configureCamera(camera, width, height);
|
||||
auto deviceSize = qApp->getDeviceSize();
|
||||
configureCamera(*(qApp->getCamera()), deviceSize.width(), deviceSize.height());
|
||||
}
|
||||
|
||||
|
||||
|
@ -91,9 +87,8 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
// left eye portal
|
||||
int portalX = 0;
|
||||
int portalY = 0;
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
QSize deviceSize = glCanvas->getDeviceSize() *
|
||||
Application::getInstance()->getRenderResolutionScale();
|
||||
QSize deviceSize = qApp->getDeviceSize() *
|
||||
qApp->getRenderResolutionScale();
|
||||
int portalW = deviceSize.width() / 2;
|
||||
int portalH = deviceSize.height();
|
||||
|
||||
|
@ -122,8 +117,9 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
glLoadIdentity(); // reset projection matrix
|
||||
glFrustum(_leftEye.left, _leftEye.right, _leftEye.bottom, _leftEye.top, nearZ, farZ); // set left view frustum
|
||||
GLfloat p[4][4];
|
||||
// Really?
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0]));
|
||||
GLfloat cotangent = p[1][1];
|
||||
float cotangent = p[1][1];
|
||||
GLfloat fov = atan(1.0f / cotangent);
|
||||
glTranslatef(_leftEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
|
||||
|
||||
|
@ -132,7 +128,7 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0));
|
||||
Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO);
|
||||
|
||||
applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
|
||||
applicationOverlay.displayOverlayTextureStereo(whichCamera, _aspect, fov);
|
||||
_activeEye = NULL;
|
||||
}
|
||||
glPopMatrix();
|
||||
|
@ -161,7 +157,7 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0));
|
||||
Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO);
|
||||
|
||||
applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
|
||||
applicationOverlay.displayOverlayTextureStereo(whichCamera, _aspect, fov);
|
||||
_activeEye = NULL;
|
||||
}
|
||||
glPopMatrix();
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include "AddressManager.h"
|
||||
#include "Application.h"
|
||||
#include "devices/OculusManager.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -97,8 +96,8 @@ int main(int argc, const char* argv[]) {
|
|||
// Oculus initialization MUST PRECEDE OpenGL context creation.
|
||||
// The nature of the Application constructor means this has to be either here,
|
||||
// or in the main window ctor, before GL startup.
|
||||
OculusManager::init();
|
||||
|
||||
Application::initPlugins();
|
||||
|
||||
int exitCode;
|
||||
{
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
|
@ -112,7 +111,7 @@ int main(int argc, const char* argv[]) {
|
|||
exitCode = app.exec();
|
||||
}
|
||||
|
||||
OculusManager::deinit();
|
||||
Application::shutdownPlugins();
|
||||
#ifdef Q_OS_WIN
|
||||
ReleaseMutex(mutex);
|
||||
#endif
|
||||
|
|
|
@ -286,8 +286,7 @@ void ControllerScriptingInterface::releaseJoystick(int joystickIndex) {
|
|||
}
|
||||
|
||||
glm::vec2 ControllerScriptingInterface::getViewportDimensions() const {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
return glm::vec2(glCanvas->width(), glCanvas->height());
|
||||
return Application::getInstance()->getCanvasSize();
|
||||
}
|
||||
|
||||
AbstractInputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <GLMHelpers.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "devices/OculusManager.h"
|
||||
|
||||
class HMDScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -41,7 +41,7 @@ WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title
|
|||
}
|
||||
|
||||
QScriptValue WindowScriptingInterface::hasFocus() {
|
||||
return Application::getInstance()->getGLWidget()->hasFocus();
|
||||
return Application::getInstance()->hasFocus();
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::setFocus() {
|
||||
|
|
|
@ -12,10 +12,13 @@
|
|||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QOpenGLTexture>
|
||||
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <PathUtils.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <PerfStat.h>
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
|
@ -26,7 +29,6 @@
|
|||
#include "Application.h"
|
||||
#include "ApplicationOverlay.h"
|
||||
#include "devices/CameraToolBox.h"
|
||||
#include "devices/OculusManager.h"
|
||||
|
||||
#include "Util.h"
|
||||
#include "ui/Stats.h"
|
||||
|
@ -46,7 +48,7 @@ const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
|
|||
|
||||
static const float MOUSE_PITCH_RANGE = 1.0f * PI;
|
||||
static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI;
|
||||
|
||||
static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE);
|
||||
|
||||
// Return a point's cartesian coordinates on a sphere from pitch and yaw
|
||||
glm::vec3 getPoint(float yaw, float pitch) {
|
||||
|
@ -134,7 +136,7 @@ void ApplicationOverlay::renderReticle(glm::quat orientation, float alpha) {
|
|||
}
|
||||
|
||||
ApplicationOverlay::ApplicationOverlay() :
|
||||
_textureFov(glm::radians(DEFAULT_OCULUS_UI_ANGULAR_SIZE)),
|
||||
_textureFov(glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE)),
|
||||
_textureAspectRatio(1.0f),
|
||||
_lastMouseMove(0),
|
||||
_magnifier(true),
|
||||
|
@ -186,10 +188,10 @@ ApplicationOverlay::~ApplicationOverlay() {
|
|||
void ApplicationOverlay::renderOverlay() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
|
||||
Overlays& overlays = qApp->getOverlays();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
_textureFov = glm::radians(_oculusUIAngularSize);
|
||||
_textureAspectRatio = (float)glCanvas->getDeviceWidth() / (float)glCanvas->getDeviceHeight();
|
||||
_textureFov = glm::radians(_hmdUIAngularSize);
|
||||
auto deviceSize = Application::getInstance()->getDeviceSize();
|
||||
_textureAspectRatio = (float)deviceSize.width() / (float)deviceSize.height();
|
||||
|
||||
//Handle fading and deactivation/activation of UI
|
||||
|
||||
|
@ -202,12 +204,12 @@ void ApplicationOverlay::renderOverlay() {
|
|||
_overlays.buildFramebufferObject();
|
||||
_overlays.bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
|
||||
glPushMatrix(); {
|
||||
const float NEAR_CLIP = -10000;
|
||||
const float FAR_CLIP = 10000;
|
||||
glLoadIdentity();
|
||||
glOrtho(0, glCanvas->width(), glCanvas->height(), 0, NEAR_CLIP, FAR_CLIP);
|
||||
glOrtho(0, deviceSize.width(), deviceSize.height(), 0, NEAR_CLIP, FAR_CLIP);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
|
@ -280,7 +282,7 @@ void ApplicationOverlay::displayOverlayTexture() {
|
|||
}
|
||||
|
||||
// Draws the FBO texture for Oculus rift.
|
||||
void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
||||
void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) {
|
||||
if (_alpha == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
@ -358,7 +360,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
}
|
||||
|
||||
// Draws the FBO texture for 3DTV.
|
||||
void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov) {
|
||||
void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov) {
|
||||
if (_alpha == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
@ -413,19 +415,19 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
overlayColor);
|
||||
});
|
||||
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
if (_crosshairTexture == 0) {
|
||||
_crosshairTexture = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/sixense-reticle.png"));
|
||||
if (!_crosshairTexture) {
|
||||
_crosshairTexture = DependencyManager::get<TextureCache>()->
|
||||
getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
|
||||
}
|
||||
|
||||
//draw the mouse pointer
|
||||
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
|
||||
|
||||
const float reticleSize = 40.0f / glCanvas->width() * quadWidth;
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
|
||||
glm::vec2 canvasSize = qApp->getCanvasSize();
|
||||
const float reticleSize = 40.0f / canvasSize.x * quadWidth;
|
||||
x -= reticleSize / 2.0f;
|
||||
y += reticleSize / 2.0f;
|
||||
const float mouseX = (qApp->getMouseX() / (float)glCanvas->width()) * quadWidth;
|
||||
const float mouseY = (1.0 - (qApp->getMouseY() / (float)glCanvas->height())) * quadHeight;
|
||||
const float mouseX = (qApp->getMouseX() / (float)canvasSize.x) * quadWidth;
|
||||
const float mouseY = (1.0 - (qApp->getMouseY() / (float)canvasSize.y)) * quadHeight;
|
||||
|
||||
glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
|
||||
|
||||
|
@ -449,24 +451,23 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
glEnable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const {
|
||||
void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) {
|
||||
const MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
const float pitch = (0.5f - y) * MOUSE_PITCH_RANGE;
|
||||
const float yaw = (0.5f - x) * MOUSE_YAW_RANGE;
|
||||
const glm::quat orientation(glm::vec3(pitch, yaw, 0.0f));
|
||||
cursorPos = 0.5f - cursorPos;
|
||||
cursorPos *= MOUSE_RANGE;
|
||||
const glm::quat orientation(glm::vec3(cursorPos, 0.0f));
|
||||
const glm::vec3 localDirection = orientation * IDENTITY_FRONT;
|
||||
|
||||
// Get cursor position
|
||||
const glm::vec3 cursorPos = myAvatar->getDefaultEyePosition() + myAvatar->getOrientation() * localDirection;
|
||||
const glm::vec3 cursorDir = myAvatar->getDefaultEyePosition() + myAvatar->getOrientation() * localDirection;
|
||||
|
||||
// Ray start where the eye position is and stop where the cursor is
|
||||
origin = myAvatar->getEyePosition();
|
||||
direction = cursorPos - origin;
|
||||
direction = cursorDir - origin;
|
||||
}
|
||||
|
||||
//Caculate the click location using one of the sixense controllers. Scale is not applied
|
||||
QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
|
||||
|
@ -477,8 +478,8 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
|
|||
glm::vec3 tipPos = invOrientation * (tip - eyePos);
|
||||
|
||||
QPoint rv;
|
||||
|
||||
if (OculusManager::isConnected()) {
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
if (qApp->isHMDMode()) {
|
||||
float t;
|
||||
|
||||
//We back the ray up by dir to ensure that it will not start inside the UI.
|
||||
|
@ -497,8 +498,8 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
|
|||
float u = asin(collisionPos.x) / (_textureFov)+0.5f;
|
||||
float v = 1.0 - (asin(collisionPos.y) / (_textureFov)+0.5f);
|
||||
|
||||
rv.setX(u * glCanvas->width());
|
||||
rv.setY(v * glCanvas->height());
|
||||
rv.setX(u * canvasSize.x);
|
||||
rv.setY(v * canvasSize.y);
|
||||
}
|
||||
} else {
|
||||
//if they did not click on the overlay, just set the coords to INT_MAX
|
||||
|
@ -515,8 +516,8 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
|
|||
ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w;
|
||||
}
|
||||
|
||||
rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * glCanvas->width());
|
||||
rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * glCanvas->height());
|
||||
rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * canvasSize.x);
|
||||
rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * canvasSize.y);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
@ -541,18 +542,17 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position,
|
|||
|
||||
//Renders optional pointers
|
||||
void ApplicationOverlay::renderPointers() {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
//lazily load crosshair texture
|
||||
if (_crosshairTexture == 0) {
|
||||
_crosshairTexture = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/sixense-reticle.png"));
|
||||
_crosshairTexture = DependencyManager::get<TextureCache>()->
|
||||
getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
|
||||
}
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
|
||||
|
||||
if (OculusManager::isConnected() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) {
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
|
||||
|
||||
if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) {
|
||||
//If we are in oculus, render reticle later
|
||||
if (_lastMouseMove == 0) {
|
||||
_lastMouseMove = usecTimestampNow();
|
||||
|
@ -563,9 +563,9 @@ void ApplicationOverlay::renderPointers() {
|
|||
if (_reticlePosition[MOUSE] != position) {
|
||||
_lastMouseMove = usecTimestampNow();
|
||||
} else if (usecTimestampNow() - _lastMouseMove > MAX_IDLE_TIME * USECS_PER_SECOND) {
|
||||
float pitch = 0.0f, yaw = 0.0f, roll = 0.0f; // radians
|
||||
OculusManager::getEulerAngles(yaw, pitch, roll);
|
||||
glm::quat orientation(glm::vec3(pitch, yaw, roll));
|
||||
//float pitch = 0.0f, yaw = 0.0f, roll = 0.0f; // radians
|
||||
//OculusManager::getEulerAngles(yaw, pitch, roll);
|
||||
glm::quat orientation = qApp->getHeadOrientation(); // (glm::vec3(pitch, yaw, roll));
|
||||
glm::vec3 result;
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
@ -576,7 +576,8 @@ void ApplicationOverlay::renderPointers() {
|
|||
glm::vec2 spericalPos = directionToSpherical(glm::normalize(lookAtDirection));
|
||||
glm::vec2 screenPos = sphericalToScreen(spericalPos);
|
||||
position = QPoint(screenPos.x, screenPos.y);
|
||||
glCanvas->cursor().setPos(glCanvas->mapToGlobal(position));
|
||||
// FIXME
|
||||
//glCanvas->cursor().setPos(glCanvas->mapToGlobal(position));
|
||||
} else {
|
||||
qDebug() << "No collision point";
|
||||
}
|
||||
|
@ -599,7 +600,6 @@ void ApplicationOverlay::renderPointers() {
|
|||
}
|
||||
|
||||
void ApplicationOverlay::renderControllerPointers() {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
//Static variables used for storing controller state
|
||||
|
@ -648,7 +648,7 @@ void ApplicationOverlay::renderControllerPointers() {
|
|||
|
||||
//if we have the oculus, we should make the cursor smaller since it will be
|
||||
//magnified
|
||||
if (OculusManager::isConnected()) {
|
||||
if (qApp->isHMDMode()) {
|
||||
|
||||
QPoint point = getPalmClickLocation(palmData);
|
||||
|
||||
|
@ -663,6 +663,7 @@ void ApplicationOverlay::renderControllerPointers() {
|
|||
continue;
|
||||
}
|
||||
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
int mouseX, mouseY;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
|
||||
QPoint res = getPalmClickLocation(palmData);
|
||||
|
@ -677,14 +678,14 @@ void ApplicationOverlay::renderControllerPointers() {
|
|||
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
|
||||
|
||||
// Get the pixel range over which the xAngle and yAngle are scaled
|
||||
float cursorRange = glCanvas->width() * SixenseManager::getInstance().getCursorPixelRangeMult();
|
||||
float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult();
|
||||
|
||||
mouseX = (glCanvas->width() / 2.0f + cursorRange * xAngle);
|
||||
mouseY = (glCanvas->height() / 2.0f + cursorRange * yAngle);
|
||||
mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle);
|
||||
mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle);
|
||||
}
|
||||
|
||||
//If the cursor is out of the screen then don't render it
|
||||
if (mouseX < 0 || mouseX >= glCanvas->width() || mouseY < 0 || mouseY >= glCanvas->height()) {
|
||||
if (mouseX < 0 || mouseX >= canvasSize.x || mouseY < 0 || mouseY >= canvasSize.y) {
|
||||
_reticleActive[index] = false;
|
||||
continue;
|
||||
}
|
||||
|
@ -709,7 +710,7 @@ void ApplicationOverlay::renderControllerPointers() {
|
|||
}
|
||||
|
||||
void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) {
|
||||
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
|
@ -746,10 +747,10 @@ void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool
|
|||
if (!_magnifier) {
|
||||
return;
|
||||
}
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
|
||||
const int widgetWidth = glCanvas->width();
|
||||
const int widgetHeight = glCanvas->height();
|
||||
const int widgetWidth = canvasSize.x;
|
||||
const int widgetHeight = canvasSize.y;
|
||||
|
||||
const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f;
|
||||
const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f;
|
||||
|
@ -819,7 +820,7 @@ void ApplicationOverlay::renderCameraToggle() {
|
|||
}
|
||||
|
||||
int audioMeterY;
|
||||
bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !OculusManager::isConnected();
|
||||
bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode();
|
||||
bool boxed = smallMirrorVisible &&
|
||||
!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror);
|
||||
if (boxed) {
|
||||
|
@ -832,7 +833,6 @@ void ApplicationOverlay::renderCameraToggle() {
|
|||
}
|
||||
|
||||
void ApplicationOverlay::renderAudioMeter() {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
auto audio = DependencyManager::get<AudioClient>();
|
||||
|
||||
// Audio VU Meter and Mute Icon
|
||||
|
@ -852,7 +852,7 @@ void ApplicationOverlay::renderAudioMeter() {
|
|||
}
|
||||
|
||||
int audioMeterY;
|
||||
bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !OculusManager::isConnected();
|
||||
bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode();
|
||||
bool boxed = smallMirrorVisible &&
|
||||
!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror);
|
||||
if (boxed) {
|
||||
|
@ -887,16 +887,17 @@ void ApplicationOverlay::renderAudioMeter() {
|
|||
}
|
||||
bool isClipping = ((audio->getTimeSinceLastClip() > 0.0f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
|
||||
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
if ((audio->getTimeSinceLastClip() > 0.0f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) {
|
||||
const float MAX_MAGNITUDE = 0.7f;
|
||||
float magnitude = MAX_MAGNITUDE * (1 - audio->getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME);
|
||||
renderCollisionOverlay(glCanvas->width(), glCanvas->height(), magnitude, 1.0f);
|
||||
renderCollisionOverlay(canvasSize.x, canvasSize.y, magnitude, 1.0f);
|
||||
}
|
||||
|
||||
DependencyManager::get<AudioToolBox>()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, cameraSpace, boxed);
|
||||
|
||||
DependencyManager::get<AudioScope>()->render(glCanvas->width(), glCanvas->height());
|
||||
DependencyManager::get<AudioIOStatsRenderer>()->render(WHITE_TEXT, glCanvas->width(), glCanvas->height());
|
||||
DependencyManager::get<AudioScope>()->render(canvasSize.x, canvasSize.y);
|
||||
DependencyManager::get<AudioIOStatsRenderer>()->render(WHITE_TEXT, canvasSize.x, canvasSize.y);
|
||||
|
||||
audioMeterY += AUDIO_METER_HEIGHT;
|
||||
|
||||
|
@ -957,7 +958,6 @@ void ApplicationOverlay::renderStatsAndLogs() {
|
|||
Application* application = Application::getInstance();
|
||||
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor();
|
||||
NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay();
|
||||
|
||||
|
@ -980,12 +980,13 @@ void ApplicationOverlay::renderStatsAndLogs() {
|
|||
|
||||
// Show on-screen msec timer
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
|
||||
QString frameTimer = QString("%1\n").arg((int)(mSecsNow % 1000));
|
||||
int timerBottom =
|
||||
(Menu::getInstance()->isOptionChecked(MenuOption::Stats))
|
||||
? 80 : 20;
|
||||
drawText(glCanvas->width() - 100, glCanvas->height() - timerBottom,
|
||||
drawText(canvasSize.x - 100, canvasSize.y - timerBottom,
|
||||
0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT);
|
||||
}
|
||||
nodeBoundsDisplay.drawOverlay();
|
||||
|
@ -995,25 +996,22 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() {
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (nodeList && !nodeList->getDomainHandler().isConnected()) {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
int width = glCanvas->width();
|
||||
int height = glCanvas->height();
|
||||
|
||||
if (width != _previousBorderWidth || height != _previousBorderHeight) {
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
if (canvasSize.x != _previousBorderWidth || canvasSize.y != _previousBorderHeight) {
|
||||
glm::vec4 color(CONNECTION_STATUS_BORDER_COLOR[0],
|
||||
CONNECTION_STATUS_BORDER_COLOR[1],
|
||||
CONNECTION_STATUS_BORDER_COLOR[2], 1.0f);
|
||||
|
||||
QVector<glm::vec2> border;
|
||||
border << glm::vec2(0, 0);
|
||||
border << glm::vec2(0, height);
|
||||
border << glm::vec2(width, height);
|
||||
border << glm::vec2(width, 0);
|
||||
border << glm::vec2(0, canvasSize.y);
|
||||
border << glm::vec2(canvasSize.x, canvasSize.y);
|
||||
border << glm::vec2(canvasSize.x, 0);
|
||||
border << glm::vec2(0, 0);
|
||||
geometryCache->updateVertices(_domainStatusBorder, border, color);
|
||||
_previousBorderWidth = width;
|
||||
_previousBorderHeight = height;
|
||||
_previousBorderWidth = canvasSize.x;
|
||||
_previousBorderHeight = canvasSize.y;
|
||||
}
|
||||
|
||||
glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH);
|
||||
|
@ -1131,8 +1129,8 @@ void ApplicationOverlay::TexturedHemisphere::cleanupVBO() {
|
|||
}
|
||||
|
||||
void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() {
|
||||
QSize size = Application::getInstance()->getGLWidget()->getDeviceSize();
|
||||
if (_framebufferObject != NULL && size == _framebufferObject->size()) {
|
||||
auto deviceSize = qApp->getDeviceSize();
|
||||
if (_framebufferObject != NULL && deviceSize == _framebufferObject->size()) {
|
||||
// Already build
|
||||
return;
|
||||
}
|
||||
|
@ -1141,7 +1139,7 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() {
|
|||
delete _framebufferObject;
|
||||
}
|
||||
|
||||
_framebufferObject = new QOpenGLFramebufferObject(size, QOpenGLFramebufferObject::Depth);
|
||||
_framebufferObject = new QOpenGLFramebufferObject(deviceSize, QOpenGLFramebufferObject::Depth);
|
||||
glBindTexture(GL_TEXTURE_2D, getTexture());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
@ -1184,7 +1182,7 @@ GLuint ApplicationOverlay::TexturedHemisphere::getTexture() {
|
|||
return _framebufferObject->texture();
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::directionToSpherical(glm::vec3 direction) const {
|
||||
glm::vec2 ApplicationOverlay::directionToSpherical(const glm::vec3& direction) {
|
||||
glm::vec2 result;
|
||||
// Compute yaw
|
||||
glm::vec3 normalProjection = glm::normalize(glm::vec3(direction.x, 0.0f, direction.z));
|
||||
|
@ -1200,47 +1198,57 @@ glm::vec2 ApplicationOverlay::directionToSpherical(glm::vec3 direction) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 ApplicationOverlay::sphericalToDirection(glm::vec2 sphericalPos) const {
|
||||
glm::vec3 ApplicationOverlay::sphericalToDirection(const glm::vec2& sphericalPos) {
|
||||
glm::quat rotation(glm::vec3(sphericalPos.y, sphericalPos.x, 0.0f));
|
||||
return rotation * IDENTITY_FRONT;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::screenToSpherical(glm::vec2 screenPos) const {
|
||||
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
|
||||
float yaw = -(screenPos.x / screenSize.width() - 0.5f) * MOUSE_YAW_RANGE;
|
||||
float pitch = (screenPos.y / screenSize.height() - 0.5f) * MOUSE_PITCH_RANGE;
|
||||
glm::vec2 ApplicationOverlay::screenToSpherical(const glm::vec2& screenPos) {
|
||||
auto screenSize = qApp->getCanvasSize();
|
||||
glm::vec2 result;
|
||||
result.x = -(screenPos.x / screenSize.x - 0.5f);
|
||||
result.y = (screenPos.y / screenSize.y - 0.5f);
|
||||
result.x *= MOUSE_YAW_RANGE;
|
||||
result.y *= MOUSE_PITCH_RANGE;
|
||||
|
||||
return glm::vec2(yaw, pitch);
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::sphericalToScreen(glm::vec2 sphericalPos) const {
|
||||
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
|
||||
float x = (-sphericalPos.x / MOUSE_YAW_RANGE + 0.5f) * screenSize.width();
|
||||
float y = (sphericalPos.y / MOUSE_PITCH_RANGE + 0.5f) * screenSize.height();
|
||||
|
||||
return glm::vec2(x, y);
|
||||
glm::vec2 ApplicationOverlay::sphericalToScreen(const glm::vec2& sphericalPos) {
|
||||
glm::vec2 result = sphericalPos;
|
||||
result.x *= -1.0;
|
||||
result /= MOUSE_RANGE;
|
||||
result += 0.5f;
|
||||
result *= qApp->getCanvasSize();
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::sphericalToOverlay(glm::vec2 sphericalPos) const {
|
||||
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
|
||||
float x = (-sphericalPos.x / (_textureFov * _textureAspectRatio) + 0.5f) * screenSize.width();
|
||||
float y = (sphericalPos.y / _textureFov + 0.5f) * screenSize.height();
|
||||
|
||||
return glm::vec2(x, y);
|
||||
glm::vec2 ApplicationOverlay::sphericalToOverlay(const glm::vec2& sphericalPos) const {
|
||||
glm::vec2 result = sphericalPos;
|
||||
result.x *= -1.0;
|
||||
result /= _textureFov;
|
||||
result.x /= _textureAspectRatio;
|
||||
result += 0.5f;
|
||||
result.x = (-sphericalPos.x / (_textureFov * _textureAspectRatio) + 0.5f);
|
||||
result.y = (sphericalPos.y / _textureFov + 0.5f);
|
||||
result *= qApp->getCanvasSize();
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::overlayToSpherical(glm::vec2 overlayPos) const {
|
||||
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
|
||||
float yaw = -(overlayPos.x / screenSize.width() - 0.5f) * _textureFov * _textureAspectRatio;
|
||||
float pitch = (overlayPos.y / screenSize.height() - 0.5f) * _textureFov;
|
||||
|
||||
return glm::vec2(yaw, pitch);
|
||||
glm::vec2 ApplicationOverlay::overlayToSpherical(const glm::vec2& overlayPos) const {
|
||||
glm::vec2 result = overlayPos;
|
||||
result.x *= -1.0;
|
||||
result /= qApp->getCanvasSize();
|
||||
result -= 0.5f;
|
||||
result *= _textureFov;
|
||||
result.x *= _textureAspectRatio;
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::screenToOverlay(glm::vec2 screenPos) const {
|
||||
glm::vec2 ApplicationOverlay::screenToOverlay(const glm::vec2& screenPos) const {
|
||||
return sphericalToOverlay(screenToSpherical(screenPos));
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::overlayToScreen(glm::vec2 overlayPos) const {
|
||||
glm::vec2 ApplicationOverlay::overlayToScreen(const glm::vec2& overlayPos) const {
|
||||
return sphericalToScreen(overlayToSpherical(overlayPos));
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef hifi_ApplicationOverlay_h
|
||||
#define hifi_ApplicationOverlay_h
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
class Camera;
|
||||
class Overlays;
|
||||
class QOpenGLFramebufferObject;
|
||||
|
@ -20,9 +21,11 @@ const float MAGNIFY_WIDTH = 220.0f;
|
|||
const float MAGNIFY_HEIGHT = 100.0f;
|
||||
const float MAGNIFY_MULT = 2.0f;
|
||||
|
||||
const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f;
|
||||
const float DEFAULT_HMD_UI_ANGULAR_SIZE = 72.0f;
|
||||
|
||||
// Handles the drawing of the overlays to the screen
|
||||
// TODO, move divide up the rendering, displaying and input handling
|
||||
// facilities of this class
|
||||
class ApplicationOverlay : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -31,19 +34,18 @@ public:
|
|||
|
||||
void renderOverlay();
|
||||
void displayOverlayTexture();
|
||||
void displayOverlayTextureOculus(Camera& whichCamera);
|
||||
void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov);
|
||||
|
||||
void computeOculusPickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const;
|
||||
void displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov);
|
||||
void displayOverlayTextureHmd(Camera& whichCamera);
|
||||
|
||||
QPoint getPalmClickLocation(const PalmData *palm) const;
|
||||
bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
|
||||
|
||||
bool hasMagnifier() const { return _magnifier; }
|
||||
void toggleMagnifier() { _magnifier = !_magnifier; }
|
||||
|
||||
float getOculusUIAngularSize() const { return _oculusUIAngularSize; }
|
||||
void setOculusUIAngularSize(float oculusUIAngularSize) { _oculusUIAngularSize = oculusUIAngularSize; }
|
||||
|
||||
float getHmdUIAngularSize() const { return _hmdUIAngularSize; }
|
||||
void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; }
|
||||
|
||||
// Converter from one frame of reference to another.
|
||||
// Frame of reference:
|
||||
// Direction: Ray that represents the spherical values
|
||||
|
@ -52,14 +54,16 @@ public:
|
|||
// Overlay: Position on the overlay (x,y)
|
||||
// (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen.
|
||||
// This allows for picking outside of the screen projection in 3D.
|
||||
glm::vec2 directionToSpherical(glm::vec3 direction) const;
|
||||
glm::vec3 sphericalToDirection(glm::vec2 sphericalPos) const;
|
||||
glm::vec2 screenToSpherical(glm::vec2 screenPos) const;
|
||||
glm::vec2 sphericalToScreen(glm::vec2 sphericalPos) const;
|
||||
glm::vec2 sphericalToOverlay(glm::vec2 sphericalPos) const;
|
||||
glm::vec2 overlayToSpherical(glm::vec2 overlayPos) const;
|
||||
glm::vec2 screenToOverlay(glm::vec2 screenPos) const;
|
||||
glm::vec2 overlayToScreen(glm::vec2 overlayPos) const;
|
||||
glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const;
|
||||
glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const;
|
||||
glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const;
|
||||
glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const;
|
||||
|
||||
static glm::vec2 directionToSpherical(const glm::vec3 & direction);
|
||||
static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos);
|
||||
static glm::vec2 screenToSpherical(const glm::vec2 & screenPos);
|
||||
static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos);
|
||||
static void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction);
|
||||
|
||||
private:
|
||||
// Interleaved vertex data
|
||||
|
@ -91,7 +95,7 @@ private:
|
|||
VerticesIndices _vbo;
|
||||
};
|
||||
|
||||
float _oculusUIAngularSize = DEFAULT_OCULUS_UI_ANGULAR_SIZE;
|
||||
float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE;
|
||||
|
||||
void renderReticle(glm::quat orientation, float alpha);
|
||||
void renderPointers();;
|
||||
|
@ -122,9 +126,8 @@ private:
|
|||
float _oculusUIRadius;
|
||||
float _trailingAudioLoudness;
|
||||
|
||||
GLuint _crosshairTexture;
|
||||
// TODO, move divide up the rendering, displaying and input handling
|
||||
// facilities of this class
|
||||
|
||||
gpu::TexturePointer _crosshairTexture;
|
||||
GLuint _newUiTexture{ 0 };
|
||||
|
||||
int _reticleQuad;
|
||||
|
|
|
@ -19,12 +19,10 @@
|
|||
#include <QScreen>
|
||||
#include <QWindow>
|
||||
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
#include "ui/HMDToolsDialog.h"
|
||||
|
||||
#include "devices/OculusManager.h"
|
||||
|
||||
HMDToolsDialog::HMDToolsDialog(QWidget* parent) :
|
||||
|
|
|
@ -38,9 +38,7 @@ void NodeBounds::draw() {
|
|||
|
||||
// Compute ray to find selected nodes later on. We can't use the pre-computed ray in Application because it centers
|
||||
// itself after the cursor disappears.
|
||||
Application* application = Application::getInstance();
|
||||
PickRay pickRay = application->getCamera()->computePickRay(application->getTrueMouseX(),
|
||||
application->getTrueMouseY());
|
||||
PickRay pickRay = qApp->computePickRay();
|
||||
|
||||
// Variables to keep track of the selected node and properties to draw the cube later if needed
|
||||
Node* selectedNode = NULL;
|
||||
|
|
|
@ -170,7 +170,7 @@ void PreferencesDialog::loadPreferences() {
|
|||
|
||||
ui.maxOctreePPSSpin->setValue(qApp->getOctreeQuery().getMaxOctreePacketsPerSecond());
|
||||
|
||||
ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationOverlay().getOculusUIAngularSize());
|
||||
ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationOverlay().getHmdUIAngularSize());
|
||||
|
||||
SixenseManager& sixense = SixenseManager::getInstance();
|
||||
ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed());
|
||||
|
@ -216,8 +216,7 @@ void PreferencesDialog::savePreferences() {
|
|||
myAvatar->setLeanScale(ui.leanScaleSpin->value());
|
||||
myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value());
|
||||
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
Application::getInstance()->resizeGL(glCanvas->width(), glCanvas->height());
|
||||
Application::getInstance()->resizeGL();
|
||||
|
||||
DependencyManager::get<AvatarManager>()->getMyAvatar()->setRealWorldFieldOfView(ui.realWorldFieldOfViewSpin->value());
|
||||
|
||||
|
@ -231,7 +230,7 @@ void PreferencesDialog::savePreferences() {
|
|||
|
||||
qApp->getOctreeQuery().setMaxOctreePacketsPerSecond(ui.maxOctreePPSSpin->value());
|
||||
|
||||
qApp->getApplicationOverlay().setOculusUIAngularSize(ui.oculusUIAngularSizeSpin->value());
|
||||
qApp->getApplicationOverlay().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
|
||||
|
||||
SixenseManager& sixense = SixenseManager::getInstance();
|
||||
sixense.setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
|
||||
|
@ -255,7 +254,7 @@ void PreferencesDialog::savePreferences() {
|
|||
audio->setOutputStarveDetectionThreshold(ui.outputStarveDetectionThresholdSpinner->value());
|
||||
audio->setOutputStarveDetectionPeriod(ui.outputStarveDetectionPeriodSpinner->value());
|
||||
|
||||
Application::getInstance()->resizeGL(glCanvas->width(), glCanvas->height());
|
||||
Application::getInstance()->resizeGL();
|
||||
|
||||
// LOD items
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <PathUtils.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "RearMirrorTools.h"
|
||||
|
@ -28,16 +29,16 @@ const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel";
|
|||
Setting::Handle<int> RearMirrorTools::rearViewZoomLevel(QStringList() << SETTINGS_GROUP_NAME << ZOOM_LEVEL_SETTINGS,
|
||||
ZoomLevel::HEAD);
|
||||
|
||||
RearMirrorTools::RearMirrorTools(QGLWidget* parent, QRect& bounds) :
|
||||
_parent(parent),
|
||||
RearMirrorTools::RearMirrorTools(QRect& bounds) :
|
||||
_bounds(bounds),
|
||||
_windowed(false),
|
||||
_fullScreen(false)
|
||||
{
|
||||
_closeTextureId = _parent->bindTexture(QImage(PathUtils::resourcesPath() + "images/close.svg"));
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
_closeTexture = textureCache->getImageTexture(PathUtils::resourcesPath() + "images/close.svg");
|
||||
|
||||
_zoomHeadTextureId = _parent->bindTexture(QImage(PathUtils::resourcesPath() + "images/plus.svg"));
|
||||
_zoomBodyTextureId = _parent->bindTexture(QImage(PathUtils::resourcesPath() + "images/minus.svg"));
|
||||
_zoomHeadTexture = textureCache->getImageTexture(PathUtils::resourcesPath() + "images/plus.svg");
|
||||
_zoomBodyTexture = textureCache->getImageTexture(PathUtils::resourcesPath() + "images/minus.svg");
|
||||
|
||||
_shrinkIconRect = QRect(ICON_PADDING, ICON_PADDING, ICON_SIZE, ICON_SIZE);
|
||||
_closeIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE);
|
||||
|
@ -46,20 +47,19 @@ RearMirrorTools::RearMirrorTools(QGLWidget* parent, QRect& bounds) :
|
|||
_headZoomIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.bottom() - ICON_PADDING - ICON_SIZE, ICON_SIZE, ICON_SIZE);
|
||||
}
|
||||
|
||||
void RearMirrorTools::render(bool fullScreen) {
|
||||
void RearMirrorTools::render(bool fullScreen, const QPoint & mousePosition) {
|
||||
if (fullScreen) {
|
||||
_fullScreen = true;
|
||||
displayIcon(_parent->geometry(), _shrinkIconRect, _closeTextureId);
|
||||
displayIcon(QRect(QPoint(), qApp->getDeviceSize()), _shrinkIconRect, _closeTexture);
|
||||
} else {
|
||||
// render rear view tools if mouse is in the bounds
|
||||
QPoint mousePosition = _parent->mapFromGlobal(QCursor::pos());
|
||||
_windowed = _bounds.contains(mousePosition.x(), mousePosition.y());
|
||||
_windowed = _bounds.contains(mousePosition);
|
||||
if (_windowed) {
|
||||
displayIcon(_bounds, _closeIconRect, _closeTextureId);
|
||||
displayIcon(_bounds, _closeIconRect, _closeTexture);
|
||||
|
||||
ZoomLevel zoomLevel = (ZoomLevel)rearViewZoomLevel.get();
|
||||
displayIcon(_bounds, _headZoomIconRect, _zoomHeadTextureId, zoomLevel == HEAD);
|
||||
displayIcon(_bounds, _bodyZoomIconRect, _zoomBodyTextureId, zoomLevel == BODY);
|
||||
displayIcon(_bounds, _headZoomIconRect, _zoomHeadTexture, zoomLevel == HEAD);
|
||||
displayIcon(_bounds, _bodyZoomIconRect, _zoomBodyTexture, zoomLevel == BODY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ bool RearMirrorTools::mousePressEvent(int x, int y) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void RearMirrorTools::displayIcon(QRect bounds, QRect iconBounds, GLuint textureId, bool selected) {
|
||||
void RearMirrorTools::displayIcon(QRect bounds, QRect iconBounds, const gpu::TexturePointer& texture, bool selected) {
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
|
@ -116,13 +116,13 @@ void RearMirrorTools::displayIcon(QRect bounds, QRect iconBounds, GLuint texture
|
|||
} else {
|
||||
quadColor = glm::vec4(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(texture));
|
||||
|
||||
glm::vec2 topLeft(iconBounds.left(), iconBounds.top());
|
||||
glm::vec2 bottomRight(iconBounds.right(), iconBounds.bottom());
|
||||
glm::vec2 texCoordTopLeft(0.0f, 1.0f);
|
||||
glm::vec2 texCoordBottomRight(1.0f, 0.0f);
|
||||
static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
|
||||
static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
|
||||
|
||||
|
|
|
@ -12,10 +12,7 @@
|
|||
#ifndef hifi_RearMirrorTools_h
|
||||
#define hifi_RearMirrorTools_h
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
#include <SettingHandle.h>
|
||||
|
||||
enum ZoomLevel {
|
||||
|
@ -26,8 +23,8 @@ enum ZoomLevel {
|
|||
class RearMirrorTools : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
RearMirrorTools(QGLWidget* parent, QRect& bounds);
|
||||
void render(bool fullScreen);
|
||||
RearMirrorTools(QRect& bounds);
|
||||
void render(bool fullScreen, const QPoint & mousePos);
|
||||
bool mousePressEvent(int x, int y);
|
||||
|
||||
static Setting::Handle<int> rearViewZoomLevel;
|
||||
|
@ -39,12 +36,10 @@ signals:
|
|||
void restoreView();
|
||||
|
||||
private:
|
||||
QGLWidget* _parent;
|
||||
QRect _bounds;
|
||||
GLuint _closeTextureId;
|
||||
GLuint _resetTextureId;
|
||||
GLuint _zoomBodyTextureId;
|
||||
GLuint _zoomHeadTextureId;
|
||||
gpu::TexturePointer _closeTexture;
|
||||
gpu::TexturePointer _zoomBodyTexture;
|
||||
gpu::TexturePointer _zoomHeadTexture;
|
||||
|
||||
QRect _closeIconRect;
|
||||
QRect _resetIconRect;
|
||||
|
@ -55,7 +50,7 @@ private:
|
|||
bool _windowed;
|
||||
bool _fullScreen;
|
||||
|
||||
void displayIcon(QRect bounds, QRect iconBounds, GLuint textureId, bool selected = false);
|
||||
void displayIcon(QRect bounds, QRect iconBounds, const gpu::TexturePointer& texture, bool selected = false);
|
||||
};
|
||||
|
||||
#endif // hifi_RearMirrorTools_h
|
||||
|
|
|
@ -75,8 +75,8 @@ SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) {
|
|||
return data;
|
||||
}
|
||||
|
||||
QString Snapshot::saveSnapshot() {
|
||||
QFile* snapshotFile = savedFileForSnapshot(false);
|
||||
QString Snapshot::saveSnapshot(QImage image) {
|
||||
QFile* snapshotFile = savedFileForSnapshot(image, false);
|
||||
|
||||
// we don't need the snapshot file, so close it, grab its filename and delete it
|
||||
snapshotFile->close();
|
||||
|
@ -88,14 +88,12 @@ QString Snapshot::saveSnapshot() {
|
|||
return snapshotPath;
|
||||
}
|
||||
|
||||
QTemporaryFile* Snapshot::saveTempSnapshot() {
|
||||
QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) {
|
||||
// return whatever we get back from saved file for snapshot
|
||||
return static_cast<QTemporaryFile*>(savedFileForSnapshot(true));;
|
||||
return static_cast<QTemporaryFile*>(savedFileForSnapshot(image, true));;
|
||||
}
|
||||
|
||||
QFile* Snapshot::savedFileForSnapshot(bool isTemporary) {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
QImage shot = glCanvas->grabFrameBuffer();
|
||||
QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary) {
|
||||
|
||||
Avatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
|
|
|
@ -42,13 +42,13 @@ private:
|
|||
|
||||
class Snapshot {
|
||||
public:
|
||||
static QString saveSnapshot();
|
||||
static QTemporaryFile* saveTempSnapshot();
|
||||
static QString saveSnapshot(QImage image);
|
||||
static QTemporaryFile* saveTempSnapshot(QImage image);
|
||||
static SnapshotMetaData* parseSnapshotData(QString snapshotPath);
|
||||
|
||||
static Setting::Handle<QString> snapshotsLocation;
|
||||
private:
|
||||
static QFile* savedFileForSnapshot(bool isTemporary);
|
||||
static QFile* savedFileForSnapshot(QImage & image, bool isTemporary);
|
||||
};
|
||||
|
||||
#endif // hifi_Snapshot_h
|
||||
|
|
|
@ -57,8 +57,8 @@ Stats::Stats():
|
|||
_octreeStatsWidth(STATS_OCTREE_MIN_WIDTH),
|
||||
_lastHorizontalOffset(0)
|
||||
{
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
resetWidth(glCanvas->width(), 0);
|
||||
auto canvasSize = Application::getInstance()->getCanvasSize();
|
||||
resetWidth(canvasSize.x, 0);
|
||||
}
|
||||
|
||||
void Stats::toggleExpanded() {
|
||||
|
@ -68,7 +68,7 @@ void Stats::toggleExpanded() {
|
|||
// called on mouse click release
|
||||
// check for clicks over stats in order to expand or contract them
|
||||
void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset) {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
auto canvasSize = Application::getInstance()->getCanvasSize();
|
||||
|
||||
if (0 != glm::compMax(glm::abs(glm::ivec2(mouseX - mouseDragStartedX, mouseY - mouseDragStartedY)))) {
|
||||
// not worried about dragging on stats
|
||||
|
@ -115,7 +115,7 @@ void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseD
|
|||
// top-right stats click
|
||||
lines = _expanded ? 11 : 3;
|
||||
statsHeight = lines * STATS_PELS_PER_LINE + 10;
|
||||
statsWidth = glCanvas->width() - statsX;
|
||||
statsWidth = canvasSize.x - statsX;
|
||||
if (mouseX > statsX && mouseX < statsX + statsWidth && mouseY > statsY && mouseY < statsY + statsHeight) {
|
||||
toggleExpanded();
|
||||
return;
|
||||
|
@ -123,8 +123,8 @@ void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseD
|
|||
}
|
||||
|
||||
void Stats::resetWidth(int width, int horizontalOffset) {
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
int extraSpace = glCanvas->width() - horizontalOffset -2
|
||||
auto canvasSize = Application::getInstance()->getCanvasSize();
|
||||
int extraSpace = canvasSize.x - horizontalOffset - 2
|
||||
- STATS_GENERAL_MIN_WIDTH
|
||||
- (Menu::getInstance()->isOptionChecked(MenuOption::TestPing) ? STATS_PING_MIN_WIDTH -1 : 0)
|
||||
- STATS_GEO_MIN_WIDTH
|
||||
|
@ -148,7 +148,7 @@ void Stats::resetWidth(int width, int horizontalOffset) {
|
|||
_pingStatsWidth += (int) extraSpace / panels;
|
||||
}
|
||||
_geoStatsWidth += (int) extraSpace / panels;
|
||||
_octreeStatsWidth += glCanvas->width() -
|
||||
_octreeStatsWidth += canvasSize.x -
|
||||
(_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3);
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ void Stats::display(
|
|||
int outKbitsPerSecond,
|
||||
int voxelPacketsToProcess)
|
||||
{
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
auto canvasSize = Application::getInstance()->getCanvasSize();
|
||||
|
||||
unsigned int backgroundColor = 0x33333399;
|
||||
int verticalOffset = 0, lines = 0;
|
||||
|
@ -211,7 +211,7 @@ void Stats::display(
|
|||
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||
|
||||
if (_lastHorizontalOffset != horizontalOffset) {
|
||||
resetWidth(glCanvas->width(), horizontalOffset);
|
||||
resetWidth(canvasSize.x, horizontalOffset);
|
||||
_lastHorizontalOffset = horizontalOffset;
|
||||
}
|
||||
|
||||
|
@ -461,7 +461,7 @@ void Stats::display(
|
|||
|
||||
lines = _expanded ? 10 : 2;
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, glCanvas->width() - horizontalOffset,
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, canvasSize.x - horizontalOffset,
|
||||
(lines + 1) * STATS_PELS_PER_LINE);
|
||||
horizontalOffset += 5;
|
||||
|
||||
|
|
|
@ -15,7 +15,12 @@
|
|||
|
||||
#include <QBuffer>
|
||||
#include <QIODevice>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QEventLoop>
|
||||
#include <ctype.h> // .obj files are not locale-specific. The C/ASCII charset applies.
|
||||
|
||||
#include <NetworkAccessManager.h>
|
||||
#include "FBXReader.h"
|
||||
#include "OBJReader.h"
|
||||
#include "Shape.h"
|
||||
|
@ -25,35 +30,14 @@
|
|||
QHash<QString, float> COMMENT_SCALE_HINTS = {{"This file uses centimeters as units", 1.0f / 100.0f},
|
||||
{"This file uses millimeters as units", 1.0f / 1000.0f}};
|
||||
|
||||
|
||||
class OBJTokenizer {
|
||||
public:
|
||||
OBJTokenizer(QIODevice* device);
|
||||
enum SpecialToken {
|
||||
NO_TOKEN = -1,
|
||||
NO_PUSHBACKED_TOKEN = -1,
|
||||
DATUM_TOKEN = 0x100,
|
||||
COMMENT_TOKEN = 0x101
|
||||
};
|
||||
int nextToken();
|
||||
const QByteArray& getDatum() const { return _datum; }
|
||||
bool isNextTokenFloat();
|
||||
void skipLine() { _device->readLine(); }
|
||||
void pushBackToken(int token) { _pushedBackToken = token; }
|
||||
void ungetChar(char ch) { _device->ungetChar(ch); }
|
||||
const QString getComment() const { return _comment; }
|
||||
|
||||
private:
|
||||
QIODevice* _device;
|
||||
QByteArray _datum;
|
||||
int _pushedBackToken;
|
||||
QString _comment;
|
||||
};
|
||||
|
||||
const QString SMART_DEFAULT_MATERIAL_NAME = "High Fidelity smart default material name";
|
||||
|
||||
OBJTokenizer::OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) {
|
||||
}
|
||||
|
||||
const QByteArray OBJTokenizer::getLineAsDatum() {
|
||||
return _device->readLine().trimmed();
|
||||
}
|
||||
|
||||
int OBJTokenizer::nextToken() {
|
||||
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
|
||||
|
@ -116,14 +100,35 @@ bool OBJTokenizer::isNextTokenFloat() {
|
|||
return ok;
|
||||
}
|
||||
|
||||
void setMeshPartDefaults(FBXMeshPart &meshPart, QString materialID) {
|
||||
glm::vec3 OBJTokenizer::getVec3() {
|
||||
auto x = getFloat(); // N.B.: getFloat() has side-effect
|
||||
auto y = getFloat(); // And order of arguments is different on Windows/Linux.
|
||||
auto z = getFloat();
|
||||
auto v = glm::vec3(x, y, z);
|
||||
while (isNextTokenFloat()) {
|
||||
// the spec(s) get(s) vague here. might be w, might be a color... chop it off.
|
||||
nextToken();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
glm::vec2 OBJTokenizer::getVec2() {
|
||||
auto v = glm::vec2(getFloat(), 1.0f - getFloat()); // OBJ has an odd sense of u, v. Also N.B.: getFloat() has side-effect
|
||||
while (isNextTokenFloat()) {
|
||||
// there can be a w, but we don't handle that
|
||||
nextToken();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID) {
|
||||
meshPart.diffuseColor = glm::vec3(1, 1, 1);
|
||||
meshPart.specularColor = glm::vec3(1, 1, 1);
|
||||
meshPart.emissiveColor = glm::vec3(0, 0, 0);
|
||||
meshPart.emissiveParams = glm::vec2(0, 1);
|
||||
meshPart.shininess = 40;
|
||||
meshPart.opacity = 1;
|
||||
|
||||
|
||||
meshPart.materialID = materialID;
|
||||
meshPart.opacity = 1.0;
|
||||
meshPart._material = model::MaterialPointer(new model::Material());
|
||||
|
@ -134,14 +139,146 @@ void setMeshPartDefaults(FBXMeshPart &meshPart, QString materialID) {
|
|||
meshPart._material->setEmissive(glm::vec3(0.0, 0.0, 0.0));
|
||||
}
|
||||
|
||||
bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
|
||||
FBXGeometry &geometry, QVector<glm::vec3>& faceNormals, QVector<int>& faceNormalIndexes,
|
||||
float& scaleGuess) {
|
||||
FBXMesh &mesh = geometry.meshes[0];
|
||||
// OBJFace
|
||||
bool OBJFace::add(const QByteArray& vertexIndex, const QByteArray& textureIndex, const QByteArray& normalIndex, const QVector<glm::vec3>& vertices) {
|
||||
bool ok;
|
||||
int index = vertexIndex.toInt(&ok);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
vertexIndices.append(index - 1);
|
||||
if (!textureIndex.isEmpty()) {
|
||||
index = textureIndex.toInt(&ok);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
if (index < 0) { // Count backwards from the last one added.
|
||||
index = vertices.count() + 1 + index;
|
||||
}
|
||||
textureUVIndices.append(index - 1);
|
||||
}
|
||||
if (!normalIndex.isEmpty()) {
|
||||
index = normalIndex.toInt(&ok);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
normalIndices.append(index - 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
QVector<OBJFace> OBJFace::triangulate() {
|
||||
QVector<OBJFace> newFaces;
|
||||
const int nVerticesInATriangle = 3;
|
||||
if (vertexIndices.count() == nVerticesInATriangle) {
|
||||
newFaces.append(*this);
|
||||
} else {
|
||||
for (int i = 1; i < vertexIndices.count() - 1; i++) {
|
||||
OBJFace newFace;
|
||||
newFace.addFrom(this, 0);
|
||||
newFace.addFrom(this, i);
|
||||
newFace.addFrom(this, i + 1);
|
||||
newFace.groupName = groupName;
|
||||
newFace.materialName = materialName;
|
||||
newFaces.append(newFace);
|
||||
}
|
||||
}
|
||||
return newFaces;
|
||||
}
|
||||
void OBJFace::addFrom(const OBJFace* face, int index) { // add using data from f at index i
|
||||
vertexIndices.append(face->vertexIndices[index]);
|
||||
if (face->textureUVIndices.count() > 0) { // Any at all. Runtime error if not consistent.
|
||||
textureUVIndices.append(face->textureUVIndices[index]);
|
||||
}
|
||||
if (face->normalIndices.count() > 0) {
|
||||
normalIndices.append(face->normalIndices[index]);
|
||||
}
|
||||
}
|
||||
|
||||
bool OBJReader::isValidTexture(const QByteArray &filename) {
|
||||
QUrl candidateUrl = url->resolved(QUrl(filename));
|
||||
QNetworkReply *netReply = request(candidateUrl, true);
|
||||
bool isValid = netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200);
|
||||
netReply->deleteLater();
|
||||
return isValid;
|
||||
}
|
||||
|
||||
void OBJReader::parseMaterialLibrary(QIODevice* device) {
|
||||
OBJTokenizer tokenizer(device);
|
||||
QString matName = SMART_DEFAULT_MATERIAL_NAME;
|
||||
OBJMaterial& currentMaterial = materials[matName];
|
||||
while (true) {
|
||||
switch (tokenizer.nextToken()) {
|
||||
case OBJTokenizer::COMMENT_TOKEN:
|
||||
qCDebug(modelformat) << "OBJ Reader MTLLIB comment:" << tokenizer.getComment();
|
||||
break;
|
||||
case OBJTokenizer::DATUM_TOKEN:
|
||||
break;
|
||||
default:
|
||||
materials[matName] = currentMaterial;
|
||||
qCDebug(modelformat) << "OBJ Reader Last material shininess:" << currentMaterial.shininess << " opacity:" << currentMaterial.opacity << " diffuse color:" << currentMaterial.diffuseColor << " specular color:" << currentMaterial.specularColor << " diffuse texture:" << currentMaterial.diffuseTextureFilename << " specular texture:" << currentMaterial.specularTextureFilename;
|
||||
return;
|
||||
}
|
||||
QByteArray token = tokenizer.getDatum();
|
||||
if (token == "newmtl") {
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
return;
|
||||
}
|
||||
materials[matName] = currentMaterial;
|
||||
matName = tokenizer.getDatum();
|
||||
currentMaterial = materials[matName];
|
||||
currentMaterial.diffuseTextureFilename = "test";
|
||||
qCDebug(modelformat) << "OBJ Reader Starting new material definition " << matName;
|
||||
currentMaterial.diffuseTextureFilename = "";
|
||||
} else if (token == "Ns") {
|
||||
currentMaterial.shininess = tokenizer.getFloat();
|
||||
} else if ((token == "d") || (token == "Tr")) {
|
||||
currentMaterial.opacity = tokenizer.getFloat();
|
||||
} else if (token == "Ka") {
|
||||
qCDebug(modelformat) << "OBJ Reader Ignoring material Ka " << tokenizer.getVec3();
|
||||
} else if (token == "Kd") {
|
||||
currentMaterial.diffuseColor = tokenizer.getVec3();
|
||||
} else if (token == "Ks") {
|
||||
currentMaterial.specularColor = tokenizer.getVec3();
|
||||
} else if ((token == "map_Kd") || (token == "map_Ks")) {
|
||||
QByteArray filename = QUrl(tokenizer.getLineAsDatum()).fileName().toUtf8();
|
||||
if (filename.endsWith(".tga")) {
|
||||
qCDebug(modelformat) << "OBJ Reader WARNING: currently ignoring tga texture " << filename << " in " << url;
|
||||
break;
|
||||
}
|
||||
if (isValidTexture(filename)) {
|
||||
if (token == "map_Kd") {
|
||||
currentMaterial.diffuseTextureFilename = filename;
|
||||
} else {
|
||||
currentMaterial.specularTextureFilename = filename;
|
||||
}
|
||||
} else {
|
||||
qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " ignoring missing texture " << filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QNetworkReply* OBJReader::request(QUrl& url, bool isTest) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest netRequest(url);
|
||||
QNetworkReply* netReply = isTest ? networkAccessManager.head(netRequest) : networkAccessManager.get(netRequest);
|
||||
QEventLoop loop; // Create an event loop that will quit when we get the finished signal
|
||||
QObject::connect(netReply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
loop.exec(); // Nothing is going to happen on this whole run thread until we get this
|
||||
netReply->waitForReadyRead(-1); // so we might as well block this thread waiting for the response, rather than
|
||||
return netReply; // trying to sync later on.
|
||||
}
|
||||
|
||||
|
||||
bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess) {
|
||||
FaceGroup faces;
|
||||
FBXMesh& mesh = geometry.meshes[0];
|
||||
mesh.parts.append(FBXMeshPart());
|
||||
FBXMeshPart &meshPart = mesh.parts.last();
|
||||
FBXMeshPart& meshPart = mesh.parts.last();
|
||||
bool sawG = false;
|
||||
bool result = true;
|
||||
int originalFaceCountForDebugging = 0;
|
||||
QString currentGroup;
|
||||
|
||||
setMeshPartDefaults(meshPart, QString("dontknow") + QString::number(mesh.parts.count()));
|
||||
|
||||
|
@ -165,6 +302,7 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
|
|||
break;
|
||||
}
|
||||
QByteArray token = tokenizer.getDatum();
|
||||
//qCDebug(modelformat) << token;
|
||||
if (token == "g") {
|
||||
if (sawG) {
|
||||
// we've encountered the beginning of the next group.
|
||||
|
@ -176,54 +314,43 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
|
|||
break;
|
||||
}
|
||||
QByteArray groupName = tokenizer.getDatum();
|
||||
meshPart.materialID = groupName;
|
||||
currentGroup = groupName;
|
||||
//qCDebug(modelformat) << "new group:" << groupName;
|
||||
} else if (token == "mtllib") {
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
break;
|
||||
}
|
||||
QByteArray libraryName = tokenizer.getDatum();
|
||||
if (librariesSeen.contains(libraryName)) {
|
||||
break; // Some files use mtllib over and over again for the same libraryName
|
||||
}
|
||||
librariesSeen[libraryName] = true;
|
||||
QUrl libraryUrl = url->resolved(QUrl(libraryName).fileName()); // Throw away any path part of libraryName, and merge against original url.
|
||||
qCDebug(modelformat) << "OBJ Reader new library:" << libraryName << " at:" << libraryUrl;
|
||||
QNetworkReply* netReply = request(libraryUrl, false);
|
||||
if (netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200)) {
|
||||
parseMaterialLibrary(netReply);
|
||||
} else {
|
||||
qCDebug(modelformat) << "OBJ Reader " << libraryName << " did not answer. Got " << netReply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||
}
|
||||
netReply->deleteLater();
|
||||
} else if (token == "usemtl") {
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
break;
|
||||
}
|
||||
currentMaterialName = tokenizer.getDatum();
|
||||
qCDebug(modelformat) << "OBJ Reader new current material:" << currentMaterialName;
|
||||
} else if (token == "v") {
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
break;
|
||||
}
|
||||
float x = std::stof(tokenizer.getDatum().data());
|
||||
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
break;
|
||||
}
|
||||
float y = std::stof(tokenizer.getDatum().data());
|
||||
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
break;
|
||||
}
|
||||
float z = std::stof(tokenizer.getDatum().data());
|
||||
|
||||
while (tokenizer.isNextTokenFloat()) {
|
||||
// the spec(s) get(s) vague here. might be w, might be a color... chop it off.
|
||||
tokenizer.nextToken();
|
||||
}
|
||||
mesh.vertices.append(glm::vec3(x, y, z));
|
||||
vertices.append(tokenizer.getVec3());
|
||||
} else if (token == "vn") {
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
break;
|
||||
}
|
||||
float x = std::stof(tokenizer.getDatum().data());
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
break;
|
||||
}
|
||||
float y = std::stof(tokenizer.getDatum().data());
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
break;
|
||||
}
|
||||
float z = std::stof(tokenizer.getDatum().data());
|
||||
|
||||
while (tokenizer.isNextTokenFloat()) {
|
||||
// the spec gets vague here. might be w
|
||||
tokenizer.nextToken();
|
||||
}
|
||||
faceNormals.append(glm::vec3(x, y, z));
|
||||
normals.append(tokenizer.getVec3());
|
||||
} else if (token == "vt") {
|
||||
textureUVs.append(tokenizer.getVec2());
|
||||
} else if (token == "f") {
|
||||
// a face can have 3 or more vertices
|
||||
QVector<int> indices;
|
||||
QVector<int> normalIndices;
|
||||
OBJFace face;
|
||||
while (true) {
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
if (indices.count() == 0) {
|
||||
if (face.vertexIndices.count() == 0) {
|
||||
// nonsense, bail out.
|
||||
goto done;
|
||||
}
|
||||
|
@ -233,69 +360,22 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
|
|||
// vertex-index
|
||||
// vertex-index/texture-index
|
||||
// vertex-index/texture-index/surface-normal-index
|
||||
|
||||
QByteArray token = tokenizer.getDatum();
|
||||
QList<QByteArray> parts = token.split('/');
|
||||
assert(parts.count() >= 1);
|
||||
assert(parts.count() <= 3);
|
||||
QByteArray vertIndexBA = parts[ 0 ];
|
||||
|
||||
bool ok;
|
||||
int vertexIndex = vertIndexBA.toInt(&ok);
|
||||
if (!ok) {
|
||||
// it wasn't #/#/#, put it back and exit this loop.
|
||||
if (!isdigit(token[0])) { // Tokenizer treats line endings as whitespace. Non-digit indicates done;
|
||||
tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN);
|
||||
break;
|
||||
}
|
||||
|
||||
// if (parts.count() > 1) {
|
||||
// QByteArray textureIndexBA = parts[ 1 ];
|
||||
// }
|
||||
|
||||
if (parts.count() > 2) {
|
||||
QByteArray normalIndexBA = parts[ 2 ];
|
||||
bool ok;
|
||||
int normalIndex = normalIndexBA.toInt(&ok);
|
||||
if (ok) {
|
||||
normalIndices.append(normalIndex - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// negative indexes count backward from the current end of the vertex list
|
||||
vertexIndex = (vertexIndex >= 0 ? vertexIndex : mesh.vertices.count() + vertexIndex + 1);
|
||||
// obj index is 1 based
|
||||
assert(vertexIndex >= 1);
|
||||
indices.append(vertexIndex - 1);
|
||||
QList<QByteArray> parts = token.split('/');
|
||||
assert(parts.count() >= 1);
|
||||
assert(parts.count() <= 3);
|
||||
const QByteArray noData {};
|
||||
face.add(parts[0], (parts.count() > 1) ? parts[1] : noData, (parts.count() > 2) ? parts[2] : noData, vertices);
|
||||
face.groupName = currentGroup;
|
||||
face.materialName = currentMaterialName;
|
||||
}
|
||||
|
||||
if (indices.count() == 3) {
|
||||
meshPart.triangleIndices.append(indices[0]);
|
||||
meshPart.triangleIndices.append(indices[1]);
|
||||
meshPart.triangleIndices.append(indices[2]);
|
||||
if (normalIndices.count() == 3) {
|
||||
faceNormalIndexes.append(normalIndices[0]);
|
||||
faceNormalIndexes.append(normalIndices[1]);
|
||||
faceNormalIndexes.append(normalIndices[2]);
|
||||
} else {
|
||||
// hmm.
|
||||
}
|
||||
} else if (indices.count() == 4) {
|
||||
meshPart.quadIndices << indices;
|
||||
} else {
|
||||
// some obj writers (maya) will write a face with lots of points.
|
||||
for (int i = 1; i < indices.count() - 1; i++) {
|
||||
// break the face into triangles
|
||||
meshPart.triangleIndices.append(indices[0]);
|
||||
meshPart.triangleIndices.append(indices[i]);
|
||||
meshPart.triangleIndices.append(indices[i+1]);
|
||||
}
|
||||
if (indices.count() == normalIndices.count()) {
|
||||
for (int i = 1; i < normalIndices.count() - 1; i++) {
|
||||
faceNormalIndexes.append(normalIndices[0]);
|
||||
faceNormalIndexes.append(normalIndices[i]);
|
||||
faceNormalIndexes.append(normalIndices[i+1]);
|
||||
}
|
||||
}
|
||||
originalFaceCountForDebugging++;
|
||||
foreach(OBJFace face, face.triangulate()) {
|
||||
faces.append(face);
|
||||
}
|
||||
} else {
|
||||
// something we don't (yet) care about
|
||||
|
@ -303,61 +383,40 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
|
|||
tokenizer.skipLine();
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (meshPart.triangleIndices.size() == 0 && meshPart.quadIndices.size() == 0) {
|
||||
// empty mesh?
|
||||
done:
|
||||
if (faces.count() == 0) { // empty mesh
|
||||
mesh.parts.pop_back();
|
||||
}
|
||||
|
||||
faceGroups.append(faces); // We're done with this group. Add the faces.
|
||||
//qCDebug(modelformat) << "end group:" << meshPart.materialID << " original faces:" << originalFaceCountForDebugging << " triangles:" << faces.count() << " keep going:" << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping) {
|
||||
FBXGeometry OBJReader::readOBJ(const QByteArray& model, const QVariantHash& mapping) {
|
||||
QBuffer buffer(const_cast<QByteArray*>(&model));
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
return readOBJ(&buffer, mapping);
|
||||
return readOBJ(&buffer, mapping, nullptr);
|
||||
}
|
||||
|
||||
|
||||
FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) {
|
||||
FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url) {
|
||||
FBXGeometry geometry;
|
||||
OBJTokenizer tokenizer(device);
|
||||
QVector<int> faceNormalIndexes;
|
||||
QVector<glm::vec3> faceNormals;
|
||||
float scaleGuess = 1.0f;
|
||||
|
||||
faceNormalIndexes.clear();
|
||||
|
||||
this->url = url;
|
||||
geometry.meshExtents.reset();
|
||||
geometry.meshes.append(FBXMesh());
|
||||
|
||||
|
||||
try {
|
||||
// call parseOBJGroup as long as it's returning true. Each successful call will
|
||||
// add a new meshPart to the geometry's single mesh.
|
||||
bool success = true;
|
||||
while (success) {
|
||||
success = parseOBJGroup(tokenizer, mapping, geometry, faceNormals, faceNormalIndexes, scaleGuess);
|
||||
}
|
||||
while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess)) {}
|
||||
|
||||
FBXMesh &mesh = geometry.meshes[0];
|
||||
FBXMesh& mesh = geometry.meshes[0];
|
||||
mesh.meshIndex = 0;
|
||||
|
||||
// if we got a hint about units, scale all the points
|
||||
if (scaleGuess != 1.0f) {
|
||||
for (int i = 0; i < mesh.vertices.size(); i++) {
|
||||
mesh.vertices[i] *= scaleGuess;
|
||||
}
|
||||
}
|
||||
|
||||
mesh.meshExtents.reset();
|
||||
foreach (const glm::vec3& vertex, mesh.vertices) {
|
||||
mesh.meshExtents.addPoint(vertex);
|
||||
geometry.meshExtents.addPoint(vertex);
|
||||
}
|
||||
|
||||
|
||||
geometry.joints.resize(1);
|
||||
geometry.joints[0].isFree = false;
|
||||
geometry.joints[0].parentIndex = -1;
|
||||
|
@ -380,63 +439,96 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) {
|
|||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
mesh.clusters.append(cluster);
|
||||
|
||||
// The OBJ format has normals for faces. The FBXGeometry structure has normals for points.
|
||||
// run through all the faces, look-up (or determine) a normal and set the normal for the points
|
||||
// that make up each face.
|
||||
QVector<glm::vec3> pointNormalsSums;
|
||||
|
||||
mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count());
|
||||
pointNormalsSums.fill(glm::vec3(0,0,0), mesh.vertices.count());
|
||||
|
||||
foreach (FBXMeshPart meshPart, mesh.parts) {
|
||||
int triCount = meshPart.triangleIndices.count() / 3;
|
||||
for (int i = 0; i < triCount; i++) {
|
||||
int p0Index = meshPart.triangleIndices[i*3];
|
||||
int p1Index = meshPart.triangleIndices[i*3+1];
|
||||
int p2Index = meshPart.triangleIndices[i*3+2];
|
||||
|
||||
assert(p0Index < mesh.vertices.count());
|
||||
assert(p1Index < mesh.vertices.count());
|
||||
assert(p2Index < mesh.vertices.count());
|
||||
|
||||
glm::vec3 n0, n1, n2;
|
||||
if (i < faceNormalIndexes.count()) {
|
||||
int n0Index = faceNormalIndexes[i*3];
|
||||
int n1Index = faceNormalIndexes[i*3+1];
|
||||
int n2Index = faceNormalIndexes[i*3+2];
|
||||
n0 = faceNormals[n0Index];
|
||||
n1 = faceNormals[n1Index];
|
||||
n2 = faceNormals[n2Index];
|
||||
} else {
|
||||
// We didn't read normals, add bogus normal data for this face
|
||||
glm::vec3 p0 = mesh.vertices[p0Index];
|
||||
glm::vec3 p1 = mesh.vertices[p1Index];
|
||||
glm::vec3 p2 = mesh.vertices[p2Index];
|
||||
n0 = glm::cross(p1 - p0, p2 - p0);
|
||||
n1 = n0;
|
||||
n2 = n0;
|
||||
}
|
||||
|
||||
// we sum up the normal for each point and then divide by the count to get an average
|
||||
pointNormalsSums[p0Index] += n0;
|
||||
pointNormalsSums[p1Index] += n1;
|
||||
pointNormalsSums[p2Index] += n2;
|
||||
|
||||
// Some .obj files use the convention that a group with uv coordinates that doesn't define a material, should use a texture with the same basename as the .obj file.
|
||||
QString filename = url->fileName();
|
||||
int extIndex = filename.lastIndexOf('.'); // by construction, this does not fail
|
||||
QString basename = filename.remove(extIndex + 1, sizeof("obj"));
|
||||
OBJMaterial& preDefinedMaterial = materials[SMART_DEFAULT_MATERIAL_NAME];
|
||||
preDefinedMaterial.diffuseColor = glm::vec3(1.0f);
|
||||
QVector<QByteArray> extensions = {"jpg", "jpeg", "png", "tga"};
|
||||
QByteArray base = basename.toUtf8(), textName = "";
|
||||
for (int i = 0; i < extensions.count(); i++) {
|
||||
QByteArray candidateString = base + extensions[i];
|
||||
if (isValidTexture(candidateString)) {
|
||||
textName = candidateString;
|
||||
break;
|
||||
}
|
||||
|
||||
int vertCount = mesh.vertices.count();
|
||||
for (int i = 0; i < vertCount; i++) {
|
||||
float length = glm::length(pointNormalsSums[i]);
|
||||
if (length > FLT_EPSILON) {
|
||||
mesh.normals[i] = glm::normalize(pointNormalsSums[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX do same normal calculation for quadCount
|
||||
}
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
qCDebug(modelformat) << "something went wrong in OBJ reader";
|
||||
if (!textName.isEmpty()) {
|
||||
preDefinedMaterial.diffuseTextureFilename = textName;
|
||||
}
|
||||
materials[SMART_DEFAULT_MATERIAL_NAME] = preDefinedMaterial;
|
||||
|
||||
for (int i = 0, meshPartCount = 0; i < mesh.parts.count(); i++, meshPartCount++) {
|
||||
FBXMeshPart& meshPart = mesh.parts[i];
|
||||
FaceGroup faceGroup = faceGroups[meshPartCount];
|
||||
OBJFace leadFace = faceGroup[0]; // All the faces in the same group will have the same name and material.
|
||||
QString groupMaterialName = leadFace.materialName;
|
||||
if (groupMaterialName.isEmpty() && (leadFace.textureUVIndices.count() > 0)) {
|
||||
qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " needs a texture that isn't specified. Using default mechanism.";
|
||||
groupMaterialName = SMART_DEFAULT_MATERIAL_NAME;
|
||||
} else if (!groupMaterialName.isEmpty() && !materials.contains(groupMaterialName)) {
|
||||
qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " specifies a material " << groupMaterialName << " that is not defined. Using default mechanism.";
|
||||
groupMaterialName = SMART_DEFAULT_MATERIAL_NAME;
|
||||
}
|
||||
if (!groupMaterialName.isEmpty()) {
|
||||
OBJMaterial* material = &materials[groupMaterialName];
|
||||
// The code behind this is in transition. Some things are set directly in the FXBMeshPart...
|
||||
meshPart.materialID = groupMaterialName;
|
||||
meshPart.diffuseTexture.filename = material->diffuseTextureFilename;
|
||||
meshPart.specularTexture.filename = material->specularTextureFilename;
|
||||
// ... and some things are set in the underlying material.
|
||||
meshPart._material->setDiffuse(material->diffuseColor);
|
||||
meshPart._material->setSpecular(material->specularColor);
|
||||
meshPart._material->setShininess(material->shininess);
|
||||
meshPart._material->setOpacity(material->opacity);
|
||||
}
|
||||
qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count();
|
||||
foreach(OBJFace face, faceGroup) {
|
||||
glm::vec3 v0 = vertices[face.vertexIndices[0]];
|
||||
glm::vec3 v1 = vertices[face.vertexIndices[1]];
|
||||
glm::vec3 v2 = vertices[face.vertexIndices[2]];
|
||||
meshPart.triangleIndices.append(mesh.vertices.count()); // not face.vertexIndices into vertices
|
||||
mesh.vertices << v0;
|
||||
meshPart.triangleIndices.append(mesh.vertices.count());
|
||||
mesh.vertices << v1;
|
||||
meshPart.triangleIndices.append(mesh.vertices.count());
|
||||
mesh.vertices << v2;
|
||||
|
||||
glm::vec3 n0, n1, n2;
|
||||
if (face.normalIndices.count()) {
|
||||
n0 = normals[face.normalIndices[0]];
|
||||
n1 = normals[face.normalIndices[1]];
|
||||
n2 = normals[face.normalIndices[2]];
|
||||
} else { // generate normals from triangle plane if not provided
|
||||
n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0);
|
||||
}
|
||||
mesh.normals << n0 << n1 << n2;
|
||||
if (face.textureUVIndices.count()) {
|
||||
mesh.texCoords
|
||||
<< textureUVs[face.textureUVIndices[0]]
|
||||
<< textureUVs[face.textureUVIndices[1]]
|
||||
<< textureUVs[face.textureUVIndices[2]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we got a hint about units, scale all the points
|
||||
if (scaleGuess != 1.0f) {
|
||||
for (int i = 0; i < mesh.vertices.size(); i++) {
|
||||
mesh.vertices[i] *= scaleGuess;
|
||||
}
|
||||
}
|
||||
|
||||
mesh.meshExtents.reset();
|
||||
foreach (const glm::vec3& vertex, mesh.vertices) {
|
||||
mesh.meshExtents.addPoint(vertex);
|
||||
geometry.meshExtents.addPoint(vertex);
|
||||
}
|
||||
fbxDebugDump(geometry);
|
||||
} catch(const std::exception& e) {
|
||||
qCDebug(modelformat) << "OBJ reader fail: " << e.what();
|
||||
}
|
||||
|
||||
return geometry;
|
||||
|
@ -453,11 +545,11 @@ void fbxDebugDump(const FBXGeometry& fbxgeo) {
|
|||
foreach (FBXMesh mesh, fbxgeo.meshes) {
|
||||
qCDebug(modelformat) << " vertices.count() =" << mesh.vertices.count();
|
||||
qCDebug(modelformat) << " normals.count() =" << mesh.normals.count();
|
||||
if (mesh.normals.count() == mesh.vertices.count()) {
|
||||
/*if (mesh.normals.count() == mesh.vertices.count()) {
|
||||
for (int i = 0; i < mesh.normals.count(); i++) {
|
||||
qCDebug(modelformat) << " " << mesh.vertices[ i ] << mesh.normals[ i ];
|
||||
}
|
||||
}
|
||||
}*/
|
||||
qCDebug(modelformat) << " tangents.count() =" << mesh.tangents.count();
|
||||
qCDebug(modelformat) << " colors.count() =" << mesh.colors.count();
|
||||
qCDebug(modelformat) << " texCoords.count() =" << mesh.texCoords.count();
|
||||
|
@ -470,13 +562,15 @@ void fbxDebugDump(const FBXGeometry& fbxgeo) {
|
|||
foreach (FBXMeshPart meshPart, mesh.parts) {
|
||||
qCDebug(modelformat) << " quadIndices.count() =" << meshPart.quadIndices.count();
|
||||
qCDebug(modelformat) << " triangleIndices.count() =" << meshPart.triangleIndices.count();
|
||||
qCDebug(modelformat) << " diffuseColor =" << meshPart.diffuseColor;
|
||||
qCDebug(modelformat) << " specularColor =" << meshPart.specularColor;
|
||||
qCDebug(modelformat) << " emissiveColor =" << meshPart.emissiveColor;
|
||||
qCDebug(modelformat) << " diffuseColor =" << meshPart.diffuseColor << "mat =" << meshPart._material->getDiffuse();
|
||||
qCDebug(modelformat) << " specularColor =" << meshPart.specularColor << "mat =" << meshPart._material->getSpecular();
|
||||
qCDebug(modelformat) << " emissiveColor =" << meshPart.emissiveColor << "mat =" << meshPart._material->getEmissive();
|
||||
qCDebug(modelformat) << " emissiveParams =" << meshPart.emissiveParams;
|
||||
qCDebug(modelformat) << " shininess =" << meshPart.shininess;
|
||||
qCDebug(modelformat) << " opacity =" << meshPart.opacity;
|
||||
qCDebug(modelformat) << " shininess =" << meshPart.shininess << "mat =" << meshPart._material->getShininess();
|
||||
qCDebug(modelformat) << " opacity =" << meshPart.opacity << "mat =" << meshPart._material->getOpacity();
|
||||
qCDebug(modelformat) << " materialID =" << meshPart.materialID;
|
||||
qCDebug(modelformat) << " diffuse texture =" << meshPart.diffuseTexture.filename;
|
||||
qCDebug(modelformat) << " specular texture =" << meshPart.specularTexture.filename;
|
||||
}
|
||||
qCDebug(modelformat) << " clusters.count() =" << mesh.clusters.count();
|
||||
foreach (FBXCluster cluster, mesh.clusters) {
|
||||
|
|
|
@ -1,8 +1,86 @@
|
|||
|
||||
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include "FBXReader.h"
|
||||
|
||||
FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping);
|
||||
FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping);
|
||||
void fbxDebugDump(const FBXGeometry& fbxgeo);
|
||||
void setMeshPartDefaults(FBXMeshPart &meshPart, QString materialID);
|
||||
class OBJTokenizer {
|
||||
public:
|
||||
OBJTokenizer(QIODevice* device);
|
||||
enum SpecialToken {
|
||||
NO_TOKEN = -1,
|
||||
NO_PUSHBACKED_TOKEN = -1,
|
||||
DATUM_TOKEN = 0x100,
|
||||
COMMENT_TOKEN = 0x101
|
||||
};
|
||||
int nextToken();
|
||||
const QByteArray& getDatum() const { return _datum; }
|
||||
bool isNextTokenFloat();
|
||||
const QByteArray getLineAsDatum(); // some "filenames" have spaces in them
|
||||
void skipLine() { _device->readLine(); }
|
||||
void pushBackToken(int token) { _pushedBackToken = token; }
|
||||
void ungetChar(char ch) { _device->ungetChar(ch); }
|
||||
const QString getComment() const { return _comment; }
|
||||
glm::vec3 getVec3();
|
||||
glm::vec2 getVec2();
|
||||
float getFloat() { return std::stof((nextToken() != OBJTokenizer::DATUM_TOKEN) ? nullptr : getDatum().data()); }
|
||||
|
||||
private:
|
||||
QIODevice* _device;
|
||||
QByteArray _datum;
|
||||
int _pushedBackToken;
|
||||
QString _comment;
|
||||
};
|
||||
|
||||
class OBJFace { // A single face, with three or more planar vertices. But see triangulate().
|
||||
public:
|
||||
QVector<int> vertexIndices;
|
||||
QVector<int> textureUVIndices;
|
||||
QVector<int> normalIndices;
|
||||
QString groupName; // We don't make use of hierarchical structure, but it can be preserved for debugging and future use.
|
||||
QString materialName;
|
||||
// Add one more set of vertex data. Answers true if successful
|
||||
bool add(const QByteArray& vertexIndex, const QByteArray& textureIndex, const QByteArray& normalIndex, const QVector<glm::vec3>& vertices);
|
||||
// Return a set of one or more OBJFaces from this one, in which each is just a triangle.
|
||||
// Even though FBXMeshPart can handle quads, it would be messy to try to keep track of mixed-size faces, so we treat everything as triangles.
|
||||
QVector<OBJFace> triangulate();
|
||||
private:
|
||||
void addFrom(const OBJFace* face, int index);
|
||||
};
|
||||
|
||||
// Materials and references to material names can come in any order, and different mesh parts can refer to the same material.
|
||||
// Therefore it would get pretty hacky to try to use FBXMeshPart to store these as we traverse the files.
|
||||
class OBJMaterial {
|
||||
public:
|
||||
float shininess;
|
||||
float opacity;
|
||||
glm::vec3 diffuseColor;
|
||||
glm::vec3 specularColor;
|
||||
QByteArray diffuseTextureFilename;
|
||||
QByteArray specularTextureFilename;
|
||||
OBJMaterial() : opacity(1.0f) {}
|
||||
};
|
||||
|
||||
class OBJReader: public QObject { // QObject so we can make network requests.
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef QVector<OBJFace> FaceGroup;
|
||||
QVector<glm::vec3> vertices; // all that we ever encounter while reading
|
||||
QVector<glm::vec2> textureUVs;
|
||||
QVector<glm::vec3> normals;
|
||||
QVector<FaceGroup> faceGroups;
|
||||
QString currentMaterialName;
|
||||
QHash<QString, OBJMaterial> materials;
|
||||
QUrl* url;
|
||||
|
||||
QNetworkReply* request(QUrl& url, bool isTest);
|
||||
FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping);
|
||||
FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url);
|
||||
private:
|
||||
QHash<QByteArray, bool> librariesSeen;
|
||||
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess);
|
||||
void parseMaterialLibrary(QIODevice* device);
|
||||
bool isValidTexture(const QByteArray &filename); // true if the file exists. TODO?: check content-type header and that it is a supported format.
|
||||
};
|
||||
|
||||
// What are these utilities doing here? One is used by fbx loading code in VHACD Utils, and the other a general debugging utility.
|
||||
void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID);
|
||||
void fbxDebugDump(const FBXGeometry& fbxgeo);
|
|
@ -50,7 +50,7 @@ public:
|
|||
virtual bool shouldRenderMesh(float largestDimension, float distanceToCamera) = 0;
|
||||
virtual float getSizeScale() const = 0;
|
||||
virtual int getBoundaryLevelAdjust() const = 0;
|
||||
virtual PickRay computePickRay(float x, float y) = 0;
|
||||
virtual PickRay computePickRay(float x, float y) const = 0;
|
||||
|
||||
virtual const glm::vec3& getAvatarPosition() const = 0;
|
||||
};
|
||||
|
|
|
@ -1797,8 +1797,8 @@ NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGe
|
|||
if (url.isEmpty()) {
|
||||
// make the minimal amount of dummy geometry to satisfy Model
|
||||
FBXJoint joint = { false, QVector<int>(), -1, 0.0f, 0.0f, glm::vec3(), glm::mat4(), glm::quat(), glm::quat(),
|
||||
glm::quat(), glm::mat4(), glm::mat4(), glm::vec3(), glm::vec3(), glm::quat(), glm::quat(),
|
||||
glm::mat4(), QString(""), glm::vec3(), glm::quat(), SHAPE_TYPE_NONE, false};
|
||||
glm::quat(), glm::mat4(), glm::mat4(), glm::vec3(), glm::vec3(), glm::quat(), glm::quat(),
|
||||
glm::mat4(), QString(""), glm::vec3(), glm::quat(), SHAPE_TYPE_NONE, false};
|
||||
_geometry.joints.append(joint);
|
||||
_geometry.leftEyeJointIndex = -1;
|
||||
_geometry.rightEyeJointIndex = -1;
|
||||
|
@ -2107,7 +2107,7 @@ void GeometryReader::run() {
|
|||
}
|
||||
fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel);
|
||||
} else if (_url.path().toLower().endsWith(".obj")) {
|
||||
fbxgeo = readOBJ(_reply, _mapping);
|
||||
fbxgeo = OBJReader().readOBJ(_reply, _mapping, &_url);
|
||||
}
|
||||
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));
|
||||
} else {
|
||||
|
|
|
@ -31,7 +31,6 @@ GlowEffect::GlowEffect()
|
|||
_isOddFrame(false),
|
||||
_isFirstFrame(true),
|
||||
_intensity(0.0f),
|
||||
_widget(NULL),
|
||||
_enabled(false) {
|
||||
}
|
||||
|
||||
|
@ -64,7 +63,7 @@ static ProgramObject* createProgram(const QString& name) {
|
|||
return program;
|
||||
}
|
||||
|
||||
void GlowEffect::init(QGLWidget* widget, bool enabled) {
|
||||
void GlowEffect::init(bool enabled) {
|
||||
if (_initialized) {
|
||||
qCDebug(renderutils, "[ERROR] GlowEffeect is already initialized.");
|
||||
return;
|
||||
|
@ -92,19 +91,9 @@ void GlowEffect::init(QGLWidget* widget, bool enabled) {
|
|||
_diffusionScaleLocation = _diffuseProgram->uniformLocation("diffusionScale");
|
||||
|
||||
_initialized = true;
|
||||
_widget = widget;
|
||||
_enabled = enabled;
|
||||
}
|
||||
|
||||
int GlowEffect::getDeviceWidth() const {
|
||||
return _widget->width() * (_widget->windowHandle() ? _widget->windowHandle()->devicePixelRatio() : 1.0f);
|
||||
}
|
||||
|
||||
int GlowEffect::getDeviceHeight() const {
|
||||
return _widget->height() * (_widget->windowHandle() ? _widget->windowHandle()->devicePixelRatio() : 1.0f);
|
||||
}
|
||||
|
||||
|
||||
void GlowEffect::prepare() {
|
||||
auto primaryFBO = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
|
||||
GLuint fbo = gpu::GLBackend::getFramebufferID(primaryFBO);
|
||||
|
@ -173,7 +162,8 @@ gpu::FramebufferPointer GlowEffect::render(bool toTexture) {
|
|||
} else {
|
||||
maybeBind(destFBO);
|
||||
if (!destFBO) {
|
||||
glViewport(0, 0, getDeviceWidth(), getDeviceHeight());
|
||||
//destFBO->getSize();
|
||||
glViewport(0, 0, framebufferSize.width(), framebufferSize.height());
|
||||
}
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
@ -219,7 +209,7 @@ gpu::FramebufferPointer GlowEffect::render(bool toTexture) {
|
|||
}
|
||||
maybeBind(destFBO);
|
||||
if (!destFBO) {
|
||||
glViewport(0, 0, getDeviceWidth(), getDeviceHeight());
|
||||
glViewport(0, 0, framebufferSize.width(), framebufferSize.height());
|
||||
}
|
||||
_addSeparateProgram->bind();
|
||||
renderFullscreenQuad();
|
||||
|
@ -228,7 +218,6 @@ gpu::FramebufferPointer GlowEffect::render(bool toTexture) {
|
|||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
/// (either the secondary or the tertiary).
|
||||
gpu::FramebufferPointer getFreeFramebuffer() const;
|
||||
|
||||
void init(QGLWidget* widget, bool enabled);
|
||||
void init(bool enabled);
|
||||
|
||||
/// Prepares the glow effect for rendering the current frame. To be called before rendering the scene.
|
||||
void prepare();
|
||||
|
@ -61,9 +61,6 @@ private:
|
|||
GlowEffect();
|
||||
virtual ~GlowEffect();
|
||||
|
||||
int getDeviceWidth() const;
|
||||
int getDeviceHeight() const;
|
||||
|
||||
bool _initialized;
|
||||
|
||||
ProgramObject* _addProgram;
|
||||
|
@ -80,7 +77,6 @@ private:
|
|||
|
||||
float _intensity;
|
||||
QStack<float> _intensityStack;
|
||||
QGLWidget* _widget;
|
||||
bool _enabled;
|
||||
};
|
||||
|
||||
|
|
|
@ -35,8 +35,7 @@ TextureCache::TextureCache() :
|
|||
_permutationNormalTexture(0),
|
||||
_whiteTexture(0),
|
||||
_blueTexture(0),
|
||||
_frameBufferSize(100, 100),
|
||||
_associatedWidget(NULL)
|
||||
_frameBufferSize(100, 100)
|
||||
{
|
||||
const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE;
|
||||
setUnusedResourceCacheSize(TEXTURE_DEFAULT_UNUSED_MAX_SIZE);
|
||||
|
@ -293,22 +292,21 @@ GLuint TextureCache::getShadowDepthTextureID() {
|
|||
return gpu::GLBackend::getTextureID(_shadowTexture);
|
||||
}
|
||||
|
||||
bool TextureCache::eventFilter(QObject* watched, QEvent* event) {
|
||||
if (event->type() == QEvent::Resize) {
|
||||
QSize size = static_cast<QResizeEvent*>(event)->size();
|
||||
if (_frameBufferSize != size) {
|
||||
_primaryFramebuffer.reset();
|
||||
_primaryColorTexture.reset();
|
||||
_primaryDepthTexture.reset();
|
||||
_primaryNormalTexture.reset();
|
||||
_primarySpecularTexture.reset();
|
||||
|
||||
_secondaryFramebuffer.reset();
|
||||
|
||||
_tertiaryFramebuffer.reset();
|
||||
}
|
||||
/// Returns a texture version of an image file
|
||||
gpu::TexturePointer TextureCache::getImageTexture(const QString & path) {
|
||||
QImage image(path);
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB);
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB);
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA);
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA);
|
||||
}
|
||||
return false;
|
||||
gpu::TexturePointer texture = gpu::TexturePointer(
|
||||
gpu::Texture::create2D(formatGPU, image.width(), image.height(),
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
texture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
texture->autoGenerateMips(-1);
|
||||
return texture;
|
||||
}
|
||||
|
||||
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
|
||||
|
@ -318,14 +316,6 @@ QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
|
|||
&Resource::allReferencesCleared);
|
||||
}
|
||||
|
||||
void TextureCache::associateWithWidget(QGLWidget* widget) {
|
||||
if (_associatedWidget) {
|
||||
_associatedWidget->removeEventFilter(this);
|
||||
}
|
||||
_associatedWidget = widget;
|
||||
_associatedWidget->installEventFilter(this);
|
||||
}
|
||||
|
||||
Texture::Texture() {
|
||||
}
|
||||
|
||||
|
@ -380,15 +370,15 @@ ImageReader::ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* r
|
|||
}
|
||||
|
||||
std::once_flag onceListSuppoertedFormatsflag;
|
||||
void listSupportedImageFormats() {
|
||||
std::call_once(onceListSuppoertedFormatsflag, [](){
|
||||
void listSupportedImageFormats() {
|
||||
std::call_once(onceListSuppoertedFormatsflag, [](){
|
||||
auto supportedFormats = QImageReader::supportedImageFormats();
|
||||
QString formats;
|
||||
foreach(const QByteArray& f, supportedFormats) {
|
||||
formats += QString(f) + ",";
|
||||
}
|
||||
qCDebug(renderutils) << "List of supported Image formats:" << formats;
|
||||
});
|
||||
qCDebug(renderutils) << "List of supported Image formats:" << formats;
|
||||
});
|
||||
}
|
||||
|
||||
void ImageReader::run() {
|
||||
|
|
|
@ -35,9 +35,6 @@ class TextureCache : public ResourceCache, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
|
||||
void associateWithWidget(QGLWidget* widget);
|
||||
|
||||
/// Sets the desired texture resolution for the framebuffer objects.
|
||||
void setFrameBufferSize(QSize frameBufferSize);
|
||||
const QSize& getFrameBufferSize() const { return _frameBufferSize; }
|
||||
|
@ -53,6 +50,9 @@ public:
|
|||
/// Returns the a pale blue texture (useful for a normal map).
|
||||
const gpu::TexturePointer& getBlueTexture();
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
gpu::TexturePointer getImageTexture(const QString & path);
|
||||
|
||||
/// Loads a texture from the specified URL.
|
||||
NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE, bool dilatable = false,
|
||||
const QByteArray& content = QByteArray());
|
||||
|
@ -94,8 +94,6 @@ public:
|
|||
/// Returns the ID of the shadow framebuffer object's depth texture.
|
||||
GLuint getShadowDepthTextureID();
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
||||
|
@ -127,7 +125,6 @@ private:
|
|||
gpu::TexturePointer _shadowTexture;
|
||||
|
||||
QSize _frameBufferSize;
|
||||
QGLWidget* _associatedWidget;
|
||||
};
|
||||
|
||||
/// A simple object wrapper for an OpenGL texture.
|
||||
|
|
|
@ -338,6 +338,10 @@ QMatrix4x4 fromGlm(const glm::mat4 & m) {
|
|||
return QMatrix4x4(&m[0][0]).transposed();
|
||||
}
|
||||
|
||||
QSize fromGlm(const glm::ivec2 & v) {
|
||||
return QSize(v.x, v.y);
|
||||
}
|
||||
|
||||
QRectF glmToRect(const glm::vec2 & pos, const glm::vec2 & size) {
|
||||
QRectF result(pos.x, pos.y, size.x, size.y);
|
||||
return result;
|
||||
|
|
|
@ -112,8 +112,13 @@ glm::vec2 toGlm(const QPointF & pt);
|
|||
glm::vec3 toGlm(const xColor & color);
|
||||
glm::vec4 toGlm(const QColor & color);
|
||||
|
||||
QSize fromGlm(const glm::ivec2 & v);
|
||||
QMatrix4x4 fromGlm(const glm::mat4 & m);
|
||||
|
||||
QRectF glmToRect(const glm::vec2 & pos, const glm::vec2 & size);
|
||||
|
||||
#define YAW(euler) euler.y
|
||||
#define PITCH(euler) euler.x
|
||||
#define ROLL(euler) euler.z
|
||||
|
||||
#endif // hifi_GLMHelpers_h
|
||||
|
|
|
@ -36,7 +36,7 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) {
|
|||
QByteArray fbxContents = fbx.readAll();
|
||||
|
||||
if (filename.toLower().endsWith(".obj")) {
|
||||
result = readOBJ(fbxContents, QVariantHash());
|
||||
result = OBJReader().readOBJ(fbxContents, QVariantHash());
|
||||
} else if (filename.toLower().endsWith(".fbx")) {
|
||||
result = readFBX(fbxContents, QVariantHash());
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue