mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 04:44:11 +02:00
merge upstream/master into andrew/isothermal
This commit is contained in:
commit
1acb90e23a
71 changed files with 2637 additions and 1004 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -46,4 +46,6 @@ libraries/audio-client/external/*/*
|
|||
gvr-interface/assets/oculussig*
|
||||
gvr-interface/libs/*
|
||||
|
||||
TAGS
|
||||
# ignore files for various dev environments
|
||||
TAGS
|
||||
*.swp
|
||||
|
|
|
@ -549,14 +549,18 @@ void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const Hif
|
|||
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
|
||||
} else if (mixerPacketType == PacketTypeMuteEnvironment) {
|
||||
QByteArray packet = receivedPacket;
|
||||
populatePacketHeader(packet, PacketTypeMuteEnvironment);
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) {
|
||||
nodeList->writeDatagram(packet, packet.size(), node);
|
||||
}
|
||||
});
|
||||
SharedNodePointer sendingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (sendingNode->getCanAdjustLocks()) {
|
||||
QByteArray packet = receivedPacket;
|
||||
populatePacketHeader(packet, PacketTypeMuteEnvironment);
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
if (node->getType() == NodeType::Agent && node->getActiveSocket() &&
|
||||
node->getLinkedData() && node != sendingNode) {
|
||||
nodeList->writeDatagram(packet, packet.size(), node);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
|
|
|
@ -508,18 +508,22 @@
|
|||
// To make this work we block the first mouseup event after the elements
|
||||
// received focus. If we block all mouseup events the user will not
|
||||
// be able to click within the selected text.
|
||||
// We also check to see if the value has changed to make sure we aren't
|
||||
// blocking a mouse-up event when clicking on an input spinner.
|
||||
var els = document.querySelectorAll("input, textarea");
|
||||
for (var i = 0; i < els.length; i++) {
|
||||
var clicked = false;
|
||||
var originalText;
|
||||
els[i].onfocus = function() {
|
||||
originalText = this.value;
|
||||
this.select();
|
||||
clicked = false;
|
||||
};
|
||||
els[i].onmouseup = function(e) {
|
||||
if (!clicked) {
|
||||
if (!clicked && originalText == this.value) {
|
||||
e.preventDefault();
|
||||
clicked = true;
|
||||
}
|
||||
clicked = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,17 +12,27 @@
|
|||
//
|
||||
|
||||
var createdRenderMenu = false;
|
||||
var createdGeneratedAudioMenu = false;
|
||||
|
||||
var ENTITIES_MENU = "Developer > Entities";
|
||||
var DEVELOPER_MENU = "Developer";
|
||||
|
||||
var ENTITIES_MENU = DEVELOPER_MENU + " > Entities";
|
||||
var COLLISION_UPDATES_TO_SERVER = "Don't send collision updates to server";
|
||||
|
||||
var RENDER_MENU = "Developer > Render";
|
||||
var RENDER_MENU = DEVELOPER_MENU + " > Render";
|
||||
var ENTITIES_ITEM = "Entities";
|
||||
var AVATARS_ITEM = "Avatars";
|
||||
|
||||
var AUDIO_MENU = DEVELOPER_MENU + " > Audio";
|
||||
var AUDIO_SOURCE_INJECT = "Generated Audio";
|
||||
var AUDIO_SOURCE_MENU = AUDIO_MENU + " > Generated Audio Source";
|
||||
var AUDIO_SOURCE_PINK_NOISE = "Pink Noise";
|
||||
var AUDIO_SOURCE_SINE_440 = "Sine 440hz";
|
||||
|
||||
|
||||
function setupMenus() {
|
||||
if (!Menu.menuExists("Developer")) {
|
||||
Menu.addMenu("Developer");
|
||||
if (!Menu.menuExists(DEVELOPER_MENU)) {
|
||||
Menu.addMenu(DEVELOPER_MENU);
|
||||
}
|
||||
if (!Menu.menuExists(ENTITIES_MENU)) {
|
||||
Menu.addMenu(ENTITIES_MENU);
|
||||
|
@ -54,6 +64,20 @@ function setupMenus() {
|
|||
if (!Menu.menuItemExists(RENDER_MENU, AVATARS_ITEM)) {
|
||||
Menu.addMenuItem({ menuName: RENDER_MENU, menuItemName: AVATARS_ITEM, isCheckable: true, isChecked: Scene.shouldRenderAvatars })
|
||||
}
|
||||
|
||||
|
||||
if (!Menu.menuExists(AUDIO_MENU)) {
|
||||
Menu.addMenu(AUDIO_MENU);
|
||||
}
|
||||
if (!Menu.menuItemExists(AUDIO_MENU, AUDIO_SOURCE_INJECT)) {
|
||||
Menu.addMenuItem({ menuName: AUDIO_MENU, menuItemName: AUDIO_SOURCE_INJECT, isCheckable: true, isChecked: false });
|
||||
Menu.addMenu(AUDIO_SOURCE_MENU);
|
||||
Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_PINK_NOISE, isCheckable: true, isChecked: false });
|
||||
Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_SINE_440, isCheckable: true, isChecked: false });
|
||||
Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, true);
|
||||
Audio.selectPinkNoise();
|
||||
createdGeneratedAudioMenu = true;
|
||||
}
|
||||
}
|
||||
|
||||
Menu.menuItemEvent.connect(function (menuItem) {
|
||||
|
@ -67,7 +91,15 @@ Menu.menuItemEvent.connect(function (menuItem) {
|
|||
Scene.shouldRenderEntities = Menu.isOptionChecked(ENTITIES_ITEM);
|
||||
} else if (menuItem == AVATARS_ITEM) {
|
||||
Scene.shouldRenderAvatars = Menu.isOptionChecked(AVATARS_ITEM);
|
||||
}
|
||||
} else if (menuItem == AUDIO_SOURCE_INJECT && !createdGeneratedAudioMenu) {
|
||||
Audio.injectGeneratedNoise(Menu.isOptionChecked(AUDIO_SOURCE_INJECT));
|
||||
} else if (menuItem == AUDIO_SOURCE_PINK_NOISE && !createdGeneratedAudioMenu) {
|
||||
Audio.selectPinkNoise();
|
||||
Menu.setIsOptionChecked(AUDIO_SOURCE_SINE_440, false);
|
||||
} else if (menuItem == AUDIO_SOURCE_SINE_440 && !createdGeneratedAudioMenu) {
|
||||
Audio.selectSine440();
|
||||
Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, false);
|
||||
}
|
||||
});
|
||||
|
||||
Scene.shouldRenderAvatarsChanged.connect(function(shouldRenderAvatars) {
|
||||
|
@ -87,6 +119,12 @@ function scriptEnding() {
|
|||
Menu.removeMenuItem(RENDER_MENU, ENTITIES_ITEM);
|
||||
Menu.removeMenuItem(RENDER_MENU, AVATARS_ITEM);
|
||||
}
|
||||
|
||||
if (createdGeneratedAudioMenu) {
|
||||
Audio.injectGeneratedNoise(false);
|
||||
Menu.removeMenuItem(AUDIO_MENU, AUDIO_SOURCE_INJECT);
|
||||
Menu.removeMenu(AUDIO_SOURCE_MENU);
|
||||
}
|
||||
}
|
||||
|
||||
setupMenus();
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include <QMouseEvent>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QObject>
|
||||
#include <QWheelEvent>
|
||||
#include <QScreen>
|
||||
|
@ -612,6 +611,10 @@ void Application::cleanupBeforeQuit() {
|
|||
|
||||
// destroy the AudioClient so it and its thread have a chance to go down safely
|
||||
DependencyManager::destroy<AudioClient>();
|
||||
|
||||
#ifdef HAVE_DDE
|
||||
DependencyManager::destroy<DdeFaceTracker>();
|
||||
#endif
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
|
@ -798,7 +801,7 @@ void Application::paintGL() {
|
|||
DependencyManager::get<GlowEffect>()->prepare();
|
||||
|
||||
// Viewport is assigned to the size of the framebuffer
|
||||
QSize size = DependencyManager::get<TextureCache>()->getPrimaryFramebufferObject()->size();
|
||||
QSize size = DependencyManager::get<TextureCache>()->getFrameBufferSize();
|
||||
glViewport(0, 0, size.width(), size.height());
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
@ -1743,8 +1746,10 @@ FaceTracker* Application::getActiveFaceTracker() {
|
|||
void Application::setActiveFaceTracker() {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
DependencyManager::get<Faceshift>()->setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift));
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_DDE
|
||||
DependencyManager::get<DdeFaceTracker>()->setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression));
|
||||
#endif
|
||||
#ifdef HAVE_VISAGE
|
||||
DependencyManager::get<Visage>()->updateEnabled();
|
||||
#endif
|
||||
|
@ -2637,8 +2642,9 @@ void Application::updateShadowMap() {
|
|||
activeRenderingThread = QThread::currentThread();
|
||||
|
||||
PerformanceTimer perfTimer("shadowMap");
|
||||
QOpenGLFramebufferObject* fbo = DependencyManager::get<TextureCache>()->getShadowFramebufferObject();
|
||||
fbo->bind();
|
||||
auto shadowFramebuffer = DependencyManager::get<TextureCache>()->getShadowFramebuffer();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(shadowFramebuffer));
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
|
@ -2654,16 +2660,18 @@ void Application::updateShadowMap() {
|
|||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
|
||||
int matrixCount = 1;
|
||||
int targetSize = fbo->width();
|
||||
//int targetSize = fbo->width();
|
||||
int sourceSize = shadowFramebuffer->getWidth();
|
||||
int targetSize = shadowFramebuffer->getWidth();
|
||||
float targetScale = 1.0f;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
|
||||
matrixCount = CASCADED_SHADOW_MATRIX_COUNT;
|
||||
targetSize = fbo->width() / 2;
|
||||
targetSize = sourceSize / 2;
|
||||
targetScale = 0.5f;
|
||||
}
|
||||
for (int i = 0; i < matrixCount; i++) {
|
||||
const glm::vec2& coord = MAP_COORDS[i];
|
||||
glViewport(coord.s * fbo->width(), coord.t * fbo->height(), targetSize, targetSize);
|
||||
glViewport(coord.s * sourceSize, coord.t * sourceSize, targetSize, targetSize);
|
||||
|
||||
// if simple shadow then since the resolution is twice as much as with cascaded, cover 2 regions with the map, not just one
|
||||
int regionIncrement = (matrixCount == 1 ? 2 : 1);
|
||||
|
@ -2786,7 +2794,7 @@ void Application::updateShadowMap() {
|
|||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
fbo->release();
|
||||
// fbo->release();
|
||||
|
||||
glViewport(0, 0, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
activeRenderingThread = nullptr;
|
||||
|
@ -2832,7 +2840,8 @@ PickRay Application::computePickRay(float x, float y) {
|
|||
}
|
||||
|
||||
QImage Application::renderAvatarBillboard() {
|
||||
DependencyManager::get<TextureCache>()->getPrimaryFramebufferObject()->bind();
|
||||
auto primaryFramebuffer = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer));
|
||||
|
||||
// the "glow" here causes an alpha of one
|
||||
Glower glower;
|
||||
|
@ -2845,7 +2854,7 @@ QImage Application::renderAvatarBillboard() {
|
|||
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
|
||||
glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
|
||||
|
||||
DependencyManager::get<TextureCache>()->getPrimaryFramebufferObject()->release();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
@ -3714,17 +3723,7 @@ bool Application::askToSetAvatarUrl(const QString& url) {
|
|||
}
|
||||
|
||||
// Download the FST file, to attempt to determine its model type
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
qCDebug(interfaceapp) << "Downloading avatar file at " << url;
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
QByteArray fstContents = reply->readAll();
|
||||
delete reply;
|
||||
QVariantHash fstMapping = FSTReader::readMapping(fstContents);
|
||||
QVariantHash fstMapping = FSTReader::downloadMapping(url);
|
||||
|
||||
FSTReader::ModelType modelType = FSTReader::predictModelType(fstMapping);
|
||||
|
||||
|
@ -3735,26 +3734,27 @@ bool Application::askToSetAvatarUrl(const QString& url) {
|
|||
QPushButton* bodyButton = NULL;
|
||||
QPushButton* bodyAndHeadButton = NULL;
|
||||
|
||||
QString modelName = fstMapping["name"].toString();
|
||||
QString message;
|
||||
QString typeInfo;
|
||||
switch (modelType) {
|
||||
case FSTReader::HEAD_MODEL:
|
||||
message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for your avatar head?");
|
||||
message = QString("Would you like to use '") + modelName + QString("' for your avatar head?");
|
||||
headButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole);
|
||||
break;
|
||||
|
||||
case FSTReader::BODY_ONLY_MODEL:
|
||||
message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for your avatar body?");
|
||||
message = QString("Would you like to use '") + modelName + QString("' for your avatar body?");
|
||||
bodyButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole);
|
||||
break;
|
||||
|
||||
case FSTReader::HEAD_AND_BODY_MODEL:
|
||||
message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for your avatar?");
|
||||
message = QString("Would you like to use '") + modelName + QString("' for your avatar?");
|
||||
bodyAndHeadButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole);
|
||||
break;
|
||||
|
||||
default:
|
||||
message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for some part of your avatar head?");
|
||||
message = QString("Would you like to use '") + modelName + QString("' for some part of your avatar head?");
|
||||
headButton = msgBox.addButton(tr("Use for Head"), QMessageBox::ActionRole);
|
||||
bodyButton = msgBox.addButton(tr("Use for Body"), QMessageBox::ActionRole);
|
||||
bodyAndHeadButton = msgBox.addButton(tr("Use for Body and Head"), QMessageBox::ActionRole);
|
||||
|
@ -3767,34 +3767,18 @@ bool Application::askToSetAvatarUrl(const QString& url) {
|
|||
msgBox.exec();
|
||||
|
||||
if (msgBox.clickedButton() == headButton) {
|
||||
qCDebug(interfaceapp) << "Chose to use for head: " << url;
|
||||
_myAvatar->setFaceModelURL(url);
|
||||
UserActivityLogger::getInstance().changedModel("head", url);
|
||||
_myAvatar->sendIdentityPacket();
|
||||
emit faceURLChanged(url);
|
||||
_myAvatar->useHeadURL(url, modelName);
|
||||
emit headURLChanged(url, modelName);
|
||||
} else if (msgBox.clickedButton() == bodyButton) {
|
||||
qCDebug(interfaceapp) << "Chose to use for body: " << url;
|
||||
_myAvatar->setSkeletonModelURL(url);
|
||||
// if the head is empty, reset it to the default head.
|
||||
if (_myAvatar->getFaceModelURLString().isEmpty()) {
|
||||
_myAvatar->setFaceModelURL(DEFAULT_HEAD_MODEL_URL);
|
||||
emit faceURLChanged(DEFAULT_HEAD_MODEL_URL.toString());
|
||||
UserActivityLogger::getInstance().changedModel("head", DEFAULT_HEAD_MODEL_URL.toString());
|
||||
}
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", url);
|
||||
_myAvatar->sendIdentityPacket();
|
||||
emit skeletonURLChanged(url);
|
||||
_myAvatar->useBodyURL(url, modelName);
|
||||
emit bodyURLChanged(url, modelName);
|
||||
} else if (msgBox.clickedButton() == bodyAndHeadButton) {
|
||||
qCDebug(interfaceapp) << "Chose to use for body + head: " << url;
|
||||
_myAvatar->setFaceModelURL(QString());
|
||||
_myAvatar->setSkeletonModelURL(url);
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", url);
|
||||
_myAvatar->sendIdentityPacket();
|
||||
emit faceURLChanged(QString());
|
||||
emit skeletonURLChanged(url);
|
||||
_myAvatar->useFullAvatarURL(url, modelName);
|
||||
emit fullAvatarURLChanged(url, modelName);
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "Declined to use the avatar: " << url;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4306,8 +4290,7 @@ void Application::checkSkeleton() {
|
|||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.exec();
|
||||
|
||||
_myAvatar->setSkeletonModelURL(DEFAULT_BODY_MODEL_URL);
|
||||
_myAvatar->sendIdentityPacket();
|
||||
_myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default");
|
||||
} else {
|
||||
_myAvatar->updateCharacterController();
|
||||
_physicsEngine.setCharacterController(_myAvatar->getCharacterController());
|
||||
|
|
|
@ -210,6 +210,8 @@ public:
|
|||
bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; }
|
||||
|
||||
FaceTracker* getActiveFaceTracker();
|
||||
void setActiveFaceTracker();
|
||||
|
||||
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
||||
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
|
@ -335,8 +337,9 @@ signals:
|
|||
void checkBackgroundDownloads();
|
||||
void domainConnectionRefused(const QString& reason);
|
||||
|
||||
void faceURLChanged(const QString& newValue);
|
||||
void skeletonURLChanged(const QString& newValue);
|
||||
void headURLChanged(const QString& newValue, const QString& modelName);
|
||||
void bodyURLChanged(const QString& newValue, const QString& modelName);
|
||||
void fullAvatarURLChanged(const QString& newValue, const QString& modelName);
|
||||
|
||||
void beforeAboutToQuit();
|
||||
|
||||
|
@ -390,8 +393,6 @@ public slots:
|
|||
|
||||
void notifyPacketVersionMismatch();
|
||||
|
||||
void setActiveFaceTracker();
|
||||
|
||||
void domainConnectionDenied(const QString& reason);
|
||||
|
||||
private slots:
|
||||
|
|
|
@ -55,6 +55,10 @@ void MainWindow::saveGeometry() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event) {
|
||||
qApp->quit();
|
||||
}
|
||||
|
||||
void MainWindow::moveEvent(QMoveEvent* event) {
|
||||
emit windowGeometryChanged(QRect(event->pos(), size()));
|
||||
QMainWindow::moveEvent(event);
|
||||
|
|
|
@ -30,6 +30,7 @@ signals:
|
|||
void windowShown(bool shown);
|
||||
|
||||
protected:
|
||||
virtual void closeEvent(QCloseEvent* event);
|
||||
virtual void moveEvent(QMoveEvent* event);
|
||||
virtual void resizeEvent(QResizeEvent* event);
|
||||
virtual void showEvent(QShowEvent* event);
|
||||
|
|
|
@ -256,7 +256,7 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false,
|
||||
qApp, SLOT(cameraMenuChanged()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H,
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::CTRL | Qt::Key_H,
|
||||
false,
|
||||
dialogsManager.data(),
|
||||
SLOT(hmdTools(bool)));
|
||||
|
@ -362,28 +362,36 @@ Menu::Menu() {
|
|||
|
||||
QAction* noFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::NoFaceTracking,
|
||||
0, true,
|
||||
qApp, SLOT(setActiveFaceTracker()));
|
||||
this, SLOT(setActiveFaceTracker()));
|
||||
faceTrackerGroup->addAction(noFaceTracker);
|
||||
|
||||
#ifdef HAVE_FACESHIFT
|
||||
QAction* faceshiftFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Faceshift,
|
||||
0, false,
|
||||
qApp, SLOT(setActiveFaceTracker()));
|
||||
this, SLOT(setActiveFaceTracker()));
|
||||
faceTrackerGroup->addAction(faceshiftFaceTracker);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DDE
|
||||
QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFaceRegression,
|
||||
0, false,
|
||||
qApp, SLOT(setActiveFaceTracker()));
|
||||
this, SLOT(setActiveFaceTracker()));
|
||||
faceTrackerGroup->addAction(ddeFaceTracker);
|
||||
|
||||
#endif
|
||||
#ifdef HAVE_VISAGE
|
||||
QAction* visageFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Visage,
|
||||
0, false,
|
||||
qApp, SLOT(setActiveFaceTracker()));
|
||||
this, SLOT(setActiveFaceTracker()));
|
||||
faceTrackerGroup->addAction(visageFaceTracker);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_DDE
|
||||
faceTrackingMenu->addSeparator();
|
||||
QAction* ddeFaceTrackerReset = addActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::ResetDDETracking,
|
||||
Qt::CTRL | Qt::Key_Apostrophe,
|
||||
DependencyManager::get<DdeFaceTracker>().data(), SLOT(resetTracking()));
|
||||
ddeFaceTrackerReset->setVisible(false);
|
||||
faceTrackingMenu->addAction(ddeFaceTrackerReset);
|
||||
#endif
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderHeadCollisionShapes);
|
||||
|
@ -483,30 +491,6 @@ Menu::Menu() {
|
|||
0,
|
||||
audioIO.data(),
|
||||
SLOT(sendMuteEnvironmentPacket()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioSourceInject,
|
||||
0,
|
||||
false,
|
||||
audioIO.data(),
|
||||
SLOT(toggleAudioSourceInject()));
|
||||
QMenu* audioSourceMenu = audioDebugMenu->addMenu("Generated Audio Source");
|
||||
{
|
||||
QAction *pinkNoise = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourcePinkNoise,
|
||||
0,
|
||||
false,
|
||||
audioIO.data(),
|
||||
SLOT(selectAudioSourcePinkNoise()));
|
||||
|
||||
QAction *sine440 = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourceSine440,
|
||||
0,
|
||||
true,
|
||||
audioIO.data(),
|
||||
SLOT(selectAudioSourceSine440()));
|
||||
|
||||
QActionGroup* audioSourceGroup = new QActionGroup(audioSourceMenu);
|
||||
audioSourceGroup->addAction(pinkNoise);
|
||||
audioSourceGroup->addAction(sine440);
|
||||
}
|
||||
|
||||
auto scope = DependencyManager::get<AudioScope>();
|
||||
|
||||
|
@ -1003,3 +987,11 @@ void Menu::visibilityChanged(Discoverability::Mode discoverabilityMode) {
|
|||
qCDebug(interfaceapp) << "ERROR Menu::visibilityChanged() called with unrecognized value.";
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::setActiveFaceTracker() {
|
||||
#ifdef HAVE_DDE
|
||||
bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression);
|
||||
Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE);
|
||||
#endif
|
||||
qApp->setActiveFaceTracker();
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ public slots:
|
|||
|
||||
private slots:
|
||||
void setVisibility();
|
||||
void setActiveFaceTracker();
|
||||
|
||||
private:
|
||||
static Menu* _instance;
|
||||
|
@ -123,9 +124,6 @@ namespace MenuOption {
|
|||
const QString AudioScopeTwentyFrames = "Twenty";
|
||||
const QString AudioStats = "Audio Stats";
|
||||
const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams";
|
||||
const QString AudioSourceInject = "Generated Audio";
|
||||
const QString AudioSourcePinkNoise = "Pink Noise";
|
||||
const QString AudioSourceSine440 = "Sine 440hz";
|
||||
const QString BandwidthDetails = "Bandwidth Details";
|
||||
const QString BlueSpeechSphere = "Blue Sphere While Speaking";
|
||||
const QString BookmarkLocation = "Bookmark Location";
|
||||
|
@ -230,6 +228,7 @@ namespace MenuOption {
|
|||
const QString RenderAmbientLight8 = "CAMPUS_SUNSET";
|
||||
const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET";
|
||||
const QString ResetAvatarSize = "Reset Avatar Size";
|
||||
const QString ResetDDETracking = "Reset DDE Tracking";
|
||||
const QString ResetSensors = "Reset Sensors";
|
||||
const QString RunningScripts = "Running Scripts";
|
||||
const QString RunTimingTests = "Run Timing Tests";
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <ShapeCollider.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <TextRenderer.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AvatarManager.h"
|
||||
|
@ -126,7 +127,7 @@ void MyAvatar::reset() {
|
|||
_skeletonModel.reset();
|
||||
getHead()->reset();
|
||||
|
||||
_velocity = glm::vec3(0.0f);
|
||||
_targetVelocity = glm::vec3(0.0f);
|
||||
setThrust(glm::vec3(0.0f));
|
||||
// Reset the pitch and roll components of the avatar's orientation, preserve yaw direction
|
||||
glm::vec3 eulers = safeEulerAngles(getOrientation());
|
||||
|
@ -605,10 +606,15 @@ void MyAvatar::saveData() {
|
|||
|
||||
settings.setValue("leanScale", _leanScale);
|
||||
settings.setValue("scale", _targetScale);
|
||||
|
||||
settings.setValue("faceModelURL", _faceModelURL);
|
||||
settings.setValue("skeletonModelURL", _skeletonModelURL);
|
||||
|
||||
|
||||
settings.setValue("useFullAvatar", _useFullAvatar);
|
||||
settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences);
|
||||
settings.setValue("faceModelURL", _headURLFromPreferences);
|
||||
settings.setValue("skeletonModelURL", _skeletonURLFromPreferences);
|
||||
settings.setValue("headModelName", _headModelName);
|
||||
settings.setValue("bodyModelName", _bodyModelName);
|
||||
settings.setValue("fullAvatarModelName", _fullAvatarModelName);
|
||||
|
||||
settings.beginWriteArray("attachmentData");
|
||||
for (int i = 0; i < _attachmentData.size(); i++) {
|
||||
settings.setArrayIndex(i);
|
||||
|
@ -640,7 +646,6 @@ void MyAvatar::saveData() {
|
|||
settings.setValue("firstFrame", pointer->getFirstFrame());
|
||||
settings.setValue("lastFrame", pointer->getLastFrame());
|
||||
settings.setValue("maskedJoints", pointer->getMaskedJoints());
|
||||
settings.setValue("running", pointer->getLoop() && pointer->isRunning());
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
|
@ -669,9 +674,54 @@ void MyAvatar::loadData() {
|
|||
_targetScale = loadSetting(settings, "scale", 1.0f);
|
||||
setScale(_scale);
|
||||
Application::getInstance()->getCamera()->setScale(_scale);
|
||||
|
||||
setFaceModelURL(settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl());
|
||||
setSkeletonModelURL(settings.value("skeletonModelURL").toUrl());
|
||||
|
||||
|
||||
// The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls
|
||||
// for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If
|
||||
// the head URL is empty, then we will assume they are using a full url...
|
||||
bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL"));
|
||||
|
||||
_useFullAvatar = settings.value("useFullAvatar").toBool();
|
||||
_headURLFromPreferences = settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl();
|
||||
_fullAvatarURLFromPreferences = settings.value("fullAvatarURL").toUrl();
|
||||
_skeletonURLFromPreferences = settings.value("skeletonModelURL").toUrl();
|
||||
_headModelName = settings.value("headModelName").toString();
|
||||
_bodyModelName = settings.value("bodyModelName").toString();
|
||||
_fullAvatarModelName = settings.value("fullAvatarModelName").toString();;
|
||||
|
||||
if (isOldSettings) {
|
||||
bool assumeFullAvatar = _headURLFromPreferences.isEmpty();
|
||||
_useFullAvatar = assumeFullAvatar;
|
||||
|
||||
if (_useFullAvatar) {
|
||||
_fullAvatarURLFromPreferences = settings.value("skeletonModelURL").toUrl();
|
||||
_headURLFromPreferences = DEFAULT_HEAD_MODEL_URL;
|
||||
_skeletonURLFromPreferences = DEFAULT_BODY_MODEL_URL;
|
||||
|
||||
QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString());
|
||||
|
||||
_headModelName = "Default";
|
||||
_bodyModelName = "Default";
|
||||
_fullAvatarModelName = fullAvatarFST["name"].toString();
|
||||
|
||||
} else {
|
||||
_fullAvatarURLFromPreferences = DEFAULT_FULL_AVATAR_MODEL_URL;
|
||||
_skeletonURLFromPreferences = settings.value("skeletonModelURL").toUrl();
|
||||
|
||||
QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString());
|
||||
QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString());
|
||||
|
||||
_headModelName = headFST["name"].toString();
|
||||
_bodyModelName = bodyFST["name"].toString();
|
||||
_fullAvatarModelName = "Default";
|
||||
}
|
||||
}
|
||||
|
||||
if (_useFullAvatar) {
|
||||
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
||||
} else {
|
||||
useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName);
|
||||
}
|
||||
|
||||
QVector<AttachmentData> attachmentData;
|
||||
int attachmentCount = settings.beginReadArray("attachmentData");
|
||||
|
@ -710,13 +760,10 @@ void MyAvatar::loadData() {
|
|||
handle->setPriority(loadSetting(settings, "priority", 1.0f));
|
||||
handle->setLoop(settings.value("loop", true).toBool());
|
||||
handle->setHold(settings.value("hold", false).toBool());
|
||||
handle->setStartAutomatically(settings.value("startAutomatically", true).toBool());
|
||||
handle->setFirstFrame(settings.value("firstFrame", 0.0f).toFloat());
|
||||
handle->setLastFrame(settings.value("lastFrame", INT_MAX).toFloat());
|
||||
handle->setMaskedJoints(settings.value("maskedJoints").toStringList());
|
||||
if (settings.value("loop", true).toBool() && settings.value("running", false).toBool()) {
|
||||
handle->setRunning(true);
|
||||
}
|
||||
handle->setStartAutomatically(settings.value("startAutomatically", true).toBool());
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
|
@ -897,6 +944,29 @@ void MyAvatar::clearJointAnimationPriorities() {
|
|||
}
|
||||
}
|
||||
|
||||
QString MyAvatar::getModelDescription() const {
|
||||
QString result;
|
||||
if (_useFullAvatar) {
|
||||
if (!getFullAvartarModelName().isEmpty()) {
|
||||
result = "Full Avatar \"" + getFullAvartarModelName() + "\"";
|
||||
} else {
|
||||
result = "Full Avatar \"" + _fullAvatarURLFromPreferences.fileName() + "\"";
|
||||
}
|
||||
} else {
|
||||
if (!getHeadModelName().isEmpty()) {
|
||||
result = "Head \"" + getHeadModelName() + "\"";
|
||||
} else {
|
||||
result = "Head \"" + _headURLFromPreferences.fileName() + "\"";
|
||||
}
|
||||
if (!getBodyModelName().isEmpty()) {
|
||||
result += " and Body \"" + getBodyModelName() + "\"";
|
||||
} else {
|
||||
result += " and Body \"" + _skeletonURLFromPreferences.fileName() + "\"";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) {
|
||||
Avatar::setFaceModelURL(faceModelURL);
|
||||
_billboardValid = false;
|
||||
|
@ -907,6 +977,74 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
|||
_billboardValid = false;
|
||||
}
|
||||
|
||||
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
|
||||
_useFullAvatar = true;
|
||||
|
||||
if (_fullAvatarURLFromPreferences != fullAvatarURL) {
|
||||
_fullAvatarURLFromPreferences = fullAvatarURL;
|
||||
if (modelName.isEmpty()) {
|
||||
QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString());
|
||||
_fullAvatarModelName = fullAvatarFST["name"].toString();
|
||||
} else {
|
||||
_fullAvatarModelName = modelName;
|
||||
}
|
||||
}
|
||||
|
||||
if (!getFaceModelURLString().isEmpty()) {
|
||||
setFaceModelURL(QString());
|
||||
}
|
||||
|
||||
if (fullAvatarURL != getSkeletonModelURL()) {
|
||||
setSkeletonModelURL(fullAvatarURL);
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", fullAvatarURL.toString());
|
||||
}
|
||||
sendIdentityPacket();
|
||||
}
|
||||
|
||||
void MyAvatar::useHeadURL(const QUrl& headURL, const QString& modelName) {
|
||||
useHeadAndBodyURLs(headURL, _skeletonURLFromPreferences, modelName, _bodyModelName);
|
||||
}
|
||||
|
||||
void MyAvatar::useBodyURL(const QUrl& bodyURL, const QString& modelName) {
|
||||
useHeadAndBodyURLs(_headURLFromPreferences, bodyURL, _headModelName, modelName);
|
||||
}
|
||||
|
||||
void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName, const QString& bodyName) {
|
||||
_useFullAvatar = false;
|
||||
|
||||
if (_headURLFromPreferences != headURL) {
|
||||
_headURLFromPreferences = headURL;
|
||||
if (headName.isEmpty()) {
|
||||
QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString());
|
||||
_headModelName = headFST["name"].toString();
|
||||
} else {
|
||||
_headModelName = headName;
|
||||
}
|
||||
}
|
||||
|
||||
if (_skeletonURLFromPreferences != bodyURL) {
|
||||
_skeletonURLFromPreferences = bodyURL;
|
||||
if (bodyName.isEmpty()) {
|
||||
QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString());
|
||||
_bodyModelName = bodyFST["name"].toString();
|
||||
} else {
|
||||
_bodyModelName = bodyName;
|
||||
}
|
||||
}
|
||||
|
||||
if (headURL != getFaceModelURL()) {
|
||||
setFaceModelURL(headURL);
|
||||
UserActivityLogger::getInstance().changedModel("head", headURL.toString());
|
||||
}
|
||||
|
||||
if (bodyURL != getSkeletonModelURL()) {
|
||||
setSkeletonModelURL(bodyURL);
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", bodyURL.toString());
|
||||
}
|
||||
sendIdentityPacket();
|
||||
}
|
||||
|
||||
|
||||
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
||||
Avatar::setAttachmentData(attachmentData);
|
||||
if (QThread::currentThread() != thread()) {
|
||||
|
@ -1240,28 +1378,28 @@ glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVe
|
|||
void MyAvatar::updatePosition(float deltaTime) {
|
||||
// rotate velocity into camera frame
|
||||
glm::quat rotation = getHead()->getCameraOrientation();
|
||||
glm::vec3 localVelocity = glm::inverse(rotation) * _velocity;
|
||||
glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity;
|
||||
|
||||
bool isHovering = _characterController.isHovering();
|
||||
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering);
|
||||
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
|
||||
|
||||
// rotate back into world-frame
|
||||
_velocity = rotation * newLocalVelocity;
|
||||
_targetVelocity = rotation * newLocalVelocity;
|
||||
|
||||
_velocity += _thrust * deltaTime;
|
||||
_targetVelocity += _thrust * deltaTime;
|
||||
_thrust = glm::vec3(0.0f);
|
||||
|
||||
// cap avatar speed
|
||||
float speed = glm::length(_velocity);
|
||||
float speed = glm::length(_targetVelocity);
|
||||
if (speed > MAX_AVATAR_SPEED) {
|
||||
_velocity *= MAX_AVATAR_SPEED / speed;
|
||||
_targetVelocity *= MAX_AVATAR_SPEED / speed;
|
||||
speed = MAX_AVATAR_SPEED;
|
||||
}
|
||||
|
||||
if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) {
|
||||
// update position ourselves
|
||||
applyPositionDelta(deltaTime * _velocity);
|
||||
applyPositionDelta(deltaTime * _targetVelocity);
|
||||
measureMotionDerivatives(deltaTime);
|
||||
} // else physics will move avatar later
|
||||
|
||||
|
|
|
@ -116,8 +116,23 @@ public:
|
|||
virtual void setJointData(int index, const glm::quat& rotation);
|
||||
virtual void clearJointData(int index);
|
||||
virtual void clearJointsData();
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
Q_INVOKABLE void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString());
|
||||
Q_INVOKABLE void useHeadURL(const QUrl& headURL, const QString& modelName = QString());
|
||||
Q_INVOKABLE void useBodyURL(const QUrl& bodyURL, const QString& modelName = QString());
|
||||
Q_INVOKABLE void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName = QString(), const QString& bodyName = QString());
|
||||
|
||||
Q_INVOKABLE bool getUseFullAvatar() const { return _useFullAvatar; }
|
||||
Q_INVOKABLE const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; }
|
||||
Q_INVOKABLE const QUrl& getHeadURLFromPreferences() const { return _headURLFromPreferences; }
|
||||
Q_INVOKABLE const QUrl& getBodyURLFromPreferences() const { return _skeletonURLFromPreferences; }
|
||||
|
||||
Q_INVOKABLE const QString& getHeadModelName() const { return _headModelName; }
|
||||
Q_INVOKABLE const QString& getBodyModelName() const { return _bodyModelName; }
|
||||
Q_INVOKABLE const QString& getFullAvartarModelName() const { return _fullAvatarModelName; }
|
||||
|
||||
Q_INVOKABLE QString getModelDescription() const;
|
||||
|
||||
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
|
||||
|
||||
virtual glm::vec3 getSkeletonPosition() const;
|
||||
|
@ -185,6 +200,11 @@ protected:
|
|||
virtual void renderAttachments(RenderArgs::RenderMode renderMode, RenderArgs* args);
|
||||
|
||||
private:
|
||||
|
||||
// These are made private for MyAvatar so that you will use the "use" methods instead
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
float _turningKeyPressTime;
|
||||
glm::vec3 _gravity;
|
||||
|
||||
|
@ -229,6 +249,16 @@ private:
|
|||
void updatePosition(float deltaTime);
|
||||
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
|
||||
void maybeUpdateBillboard();
|
||||
|
||||
// Avatar Preferences
|
||||
bool _useFullAvatar = false;
|
||||
QUrl _fullAvatarURLFromPreferences;
|
||||
QUrl _headURLFromPreferences;
|
||||
QUrl _skeletonURLFromPreferences;
|
||||
|
||||
QString _headModelName;
|
||||
QString _bodyModelName;
|
||||
QString _fullAvatarModelName;
|
||||
};
|
||||
|
||||
#endif // hifi_MyAvatar_h
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
@ -19,10 +20,21 @@
|
|||
#include "DdeFaceTracker.h"
|
||||
#include "FaceshiftConstants.h"
|
||||
#include "InterfaceLogging.h"
|
||||
#include "Menu.h"
|
||||
|
||||
|
||||
static const QHostAddress DDE_FEATURE_POINT_SERVER_ADDR("127.0.0.1");
|
||||
static const quint16 DDE_FEATURE_POINT_SERVER_PORT = 5555;
|
||||
static const QHostAddress DDE_SERVER_ADDR("127.0.0.1");
|
||||
static const quint16 DDE_SERVER_PORT = 64204;
|
||||
static const quint16 DDE_CONTROL_PORT = 64205;
|
||||
#if defined(Q_OS_WIN)
|
||||
static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde.exe";
|
||||
#elif defined(Q_OS_MAC)
|
||||
static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde.app/Contents/MacOS/dde";
|
||||
#endif
|
||||
static const QStringList DDE_ARGUMENTS = QStringList()
|
||||
<< "--udp=" + DDE_SERVER_ADDR.toString() + ":" + QString::number(DDE_SERVER_PORT)
|
||||
<< "--receiver=" + QString::number(DDE_CONTROL_PORT)
|
||||
<< "--headless";
|
||||
|
||||
static const int NUM_EXPRESSIONS = 46;
|
||||
static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSIONS) * sizeof(float) + sizeof(int);
|
||||
|
@ -121,14 +133,16 @@ struct Packet {
|
|||
};
|
||||
|
||||
DdeFaceTracker::DdeFaceTracker() :
|
||||
DdeFaceTracker(QHostAddress::Any, DDE_FEATURE_POINT_SERVER_PORT)
|
||||
DdeFaceTracker(QHostAddress::Any, DDE_SERVER_PORT, DDE_CONTROL_PORT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
||||
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort) :
|
||||
_ddeProcess(NULL),
|
||||
_host(host),
|
||||
_port(port),
|
||||
_serverPort(serverPort),
|
||||
_controlPort(controlPort),
|
||||
_lastReceiveTimestamp(0),
|
||||
_reset(false),
|
||||
_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||
|
@ -157,17 +171,50 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
|||
}
|
||||
|
||||
DdeFaceTracker::~DdeFaceTracker() {
|
||||
if (_udpSocket.isOpen()) {
|
||||
_udpSocket.close();
|
||||
}
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
void DdeFaceTracker::setEnabled(bool enabled) {
|
||||
#ifdef HAVE_DDE
|
||||
// isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket.
|
||||
_udpSocket.close();
|
||||
if (enabled) {
|
||||
_udpSocket.bind(_host, _port);
|
||||
_udpSocket.bind(_host, _serverPort);
|
||||
}
|
||||
|
||||
if (enabled && !_ddeProcess) {
|
||||
// Terminate any existing DDE process, perhaps left running after an Interface crash
|
||||
const char* DDE_EXIT_COMMAND = "exit";
|
||||
_udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
||||
|
||||
qDebug() << "[Info] DDE Face Tracker Starting";
|
||||
_ddeProcess = new QProcess(qApp);
|
||||
connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus)));
|
||||
_ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS);
|
||||
}
|
||||
|
||||
if (!enabled && _ddeProcess) {
|
||||
_ddeProcess->kill(); // More robust than trying to send an "exit" command to DDE
|
||||
_ddeProcess = NULL;
|
||||
qDebug() << "[Info] DDE Face Tracker Stopped";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DdeFaceTracker::processFinished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
if (_ddeProcess) {
|
||||
// DDE crashed or was manually terminated
|
||||
qDebug() << "[Info] DDE Face Tracker Stopped Unexpectedly";
|
||||
_udpSocket.close();
|
||||
_ddeProcess = NULL;
|
||||
Menu::getInstance()->setIsOptionChecked(MenuOption::NoFaceTracking, true);
|
||||
}
|
||||
}
|
||||
|
||||
void DdeFaceTracker::resetTracking() {
|
||||
qDebug() << "[Info] Reset DDE Tracking";
|
||||
const char* DDE_RESET_COMMAND = "reset";
|
||||
_udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
||||
}
|
||||
|
||||
bool DdeFaceTracker::isActive() const {
|
||||
|
@ -239,7 +286,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
|||
}
|
||||
|
||||
// Compute relative translation
|
||||
float LEAN_DAMPING_FACTOR = 200.0f;
|
||||
float LEAN_DAMPING_FACTOR = 75.0f;
|
||||
translation -= _referenceTranslation;
|
||||
translation /= LEAN_DAMPING_FACTOR;
|
||||
translation.x *= -1;
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
#ifndef hifi_DdeFaceTracker_h
|
||||
#define hifi_DdeFaceTracker_h
|
||||
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_OSX)
|
||||
#define HAVE_DDE
|
||||
#endif
|
||||
|
||||
#include <QProcess>
|
||||
#include <QUdpSocket>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
@ -45,9 +50,11 @@ public:
|
|||
|
||||
public slots:
|
||||
void setEnabled(bool enabled);
|
||||
void resetTracking();
|
||||
|
||||
private slots:
|
||||
|
||||
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
//sockets
|
||||
void socketErrorOccurred(QAbstractSocket::SocketError socketError);
|
||||
void readPendingDatagrams();
|
||||
|
@ -55,11 +62,14 @@ private slots:
|
|||
|
||||
private:
|
||||
DdeFaceTracker();
|
||||
DdeFaceTracker(const QHostAddress& host, quint16 port);
|
||||
DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort);
|
||||
~DdeFaceTracker();
|
||||
|
||||
QProcess* _ddeProcess;
|
||||
|
||||
QHostAddress _host;
|
||||
quint16 _port;
|
||||
quint16 _serverPort;
|
||||
quint16 _controlPort;
|
||||
|
||||
float getBlendshapeCoefficient(int index) const;
|
||||
void decodePacket(const QByteArray& buffer);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include <QDesktopWidget>
|
||||
#include <QGuiApplication>
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QScreen>
|
||||
#include <QOpenGLTimerQuery>
|
||||
|
||||
|
@ -35,6 +34,8 @@
|
|||
#include "InterfaceLogging.h"
|
||||
#include "Application.h"
|
||||
|
||||
#include <gpu/GLBackend.h>
|
||||
|
||||
template <typename Function>
|
||||
void for_each_eye(Function function) {
|
||||
for (ovrEyeType eye = ovrEyeType::ovrEye_Left;
|
||||
|
@ -114,8 +115,11 @@ void OculusManager::initSdk() {
|
|||
}
|
||||
|
||||
void OculusManager::shutdownSdk() {
|
||||
ovrHmd_Destroy(_ovrHmd);
|
||||
ovr_Shutdown();
|
||||
if (_ovrHmd) {
|
||||
ovrHmd_Destroy(_ovrHmd);
|
||||
_ovrHmd = nullptr;
|
||||
ovr_Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void OculusManager::init() {
|
||||
|
@ -124,6 +128,12 @@ void OculusManager::init() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::deinit() {
|
||||
#ifdef OVR_DIRECT_MODE
|
||||
shutdownSdk();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::connect() {
|
||||
#ifndef OVR_DIRECT_MODE
|
||||
initSdk();
|
||||
|
@ -521,7 +531,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) {
|
||||
DependencyManager::get<GlowEffect>()->prepare();
|
||||
} else {
|
||||
DependencyManager::get<TextureCache>()->getPrimaryFramebufferObject()->bind();
|
||||
auto primaryFBO = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFBO));
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
|
@ -612,15 +623,15 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
|
||||
glPopMatrix();
|
||||
|
||||
QOpenGLFramebufferObject * finalFbo = nullptr;
|
||||
gpu::FramebufferPointer finalFbo;
|
||||
//Bind the output texture from the glow shader. If glow effect is disabled, we just grab the texture
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) {
|
||||
//Full texture viewport for glow effect
|
||||
glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h);
|
||||
finalFbo = DependencyManager::get<GlowEffect>()->render(true);
|
||||
} else {
|
||||
finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebufferObject();
|
||||
finalFbo->release();
|
||||
finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
@ -644,7 +655,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
//Left over from when OR was not connected.
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, finalFbo->texture());
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)));
|
||||
|
||||
//Renders the distorted mesh onto the screen
|
||||
renderDistortionMesh(eyeRenderPose);
|
||||
|
|
|
@ -51,6 +51,7 @@ class Text3DOverlay;
|
|||
class OculusManager {
|
||||
public:
|
||||
static void init();
|
||||
static void deinit();
|
||||
static void connect();
|
||||
static void disconnect();
|
||||
static bool isConnected();
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <GlowEffect.h>
|
||||
|
|
|
@ -112,6 +112,7 @@ int main(int argc, const char* argv[]) {
|
|||
exitCode = app.exec();
|
||||
}
|
||||
|
||||
OculusManager::deinit();
|
||||
#ifdef Q_OS_WIN
|
||||
ReleaseMutex(mutex);
|
||||
#endif
|
||||
|
|
210
interface/src/ui/AvatarAppearanceDialog.cpp
Normal file
210
interface/src/ui/AvatarAppearanceDialog.cpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
//
|
||||
// AvatarAppearanceDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 2/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QFont>
|
||||
|
||||
#include <AudioClient.h>
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <devices/Faceshift.h>
|
||||
#include <devices/SixenseManager.h>
|
||||
#include <NetworkingConstants.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
#include "LODManager.h"
|
||||
#include "Menu.h"
|
||||
#include "AvatarAppearanceDialog.h"
|
||||
#include "Snapshot.h"
|
||||
#include "UserActivityLogger.h"
|
||||
#include "UIUtil.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
#include "ui/PreferencesDialog.h"
|
||||
|
||||
AvatarAppearanceDialog::AvatarAppearanceDialog(QWidget* parent) :
|
||||
QDialog(parent) {
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
ui.setupUi(this);
|
||||
|
||||
loadAvatarAppearance();
|
||||
|
||||
connect(ui.defaultButton, &QPushButton::clicked, this, &AvatarAppearanceDialog::accept);
|
||||
|
||||
connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &AvatarAppearanceDialog::openHeadModelBrowser);
|
||||
connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &AvatarAppearanceDialog::openBodyModelBrowser);
|
||||
connect(ui.buttonBrowseFullAvatar, &QPushButton::clicked, this, &AvatarAppearanceDialog::openFullAvatarModelBrowser);
|
||||
|
||||
connect(ui.useSeparateBodyAndHead, &QRadioButton::clicked, this, &AvatarAppearanceDialog::useSeparateBodyAndHead);
|
||||
connect(ui.useFullAvatar, &QRadioButton::clicked, this, &AvatarAppearanceDialog::useFullAvatar);
|
||||
|
||||
connect(Application::getInstance(), &Application::headURLChanged, this, &AvatarAppearanceDialog::headURLChanged);
|
||||
connect(Application::getInstance(), &Application::bodyURLChanged, this, &AvatarAppearanceDialog::bodyURLChanged);
|
||||
connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &AvatarAppearanceDialog::fullAvatarURLChanged);
|
||||
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
ui.bodyNameLabel->setText("Body - " + myAvatar->getBodyModelName());
|
||||
ui.headNameLabel->setText("Head - " + myAvatar->getHeadModelName());
|
||||
ui.fullAvatarNameLabel->setText("Full Avatar - " + myAvatar->getFullAvartarModelName());
|
||||
|
||||
UIUtil::scaleWidgetFontSizes(this);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::useSeparateBodyAndHead(bool checked) {
|
||||
QUrl headURL(ui.faceURLEdit->text());
|
||||
QUrl bodyURL(ui.skeletonURLEdit->text());
|
||||
DependencyManager::get<AvatarManager>()->getMyAvatar()->useHeadAndBodyURLs(headURL, bodyURL);
|
||||
setUseFullAvatar(!checked);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::useFullAvatar(bool checked) {
|
||||
QUrl fullAvatarURL(ui.fullAvatarURLEdit->text());
|
||||
DependencyManager::get<AvatarManager>()->getMyAvatar()->useFullAvatarURL(fullAvatarURL);
|
||||
setUseFullAvatar(checked);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::setUseFullAvatar(bool useFullAvatar) {
|
||||
_useFullAvatar = useFullAvatar;
|
||||
ui.faceURLEdit->setEnabled(!_useFullAvatar);
|
||||
ui.skeletonURLEdit->setEnabled(!_useFullAvatar);
|
||||
ui.fullAvatarURLEdit->setEnabled(_useFullAvatar);
|
||||
|
||||
ui.useFullAvatar->setChecked(_useFullAvatar);
|
||||
ui.useSeparateBodyAndHead->setChecked(!_useFullAvatar);
|
||||
|
||||
DependencyManager::get<DialogsManager>()->getPreferencesDialog()->avatarDescriptionChanged();
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::headURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.faceURLEdit->setText(newValue);
|
||||
setUseFullAvatar(false);
|
||||
ui.headNameLabel->setText("Head - " + modelName);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::bodyURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.skeletonURLEdit->setText(newValue);
|
||||
setUseFullAvatar(false);
|
||||
ui.bodyNameLabel->setText("Body - " + modelName);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.fullAvatarURLEdit->setText(newValue);
|
||||
setUseFullAvatar(true);
|
||||
ui.fullAvatarNameLabel->setText("Full Avatar - " + modelName);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::accept() {
|
||||
saveAvatarAppearance();
|
||||
|
||||
DependencyManager::get<DialogsManager>()->getPreferencesDialog()->avatarDescriptionChanged();
|
||||
|
||||
close();
|
||||
delete _marketplaceWindow;
|
||||
_marketplaceWindow = NULL;
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::setHeadUrl(QString modelUrl) {
|
||||
ui.faceURLEdit->setText(modelUrl);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::setSkeletonUrl(QString modelUrl) {
|
||||
ui.skeletonURLEdit->setText(modelUrl);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::openFullAvatarModelBrowser() {
|
||||
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
|
||||
auto WIDTH = 900;
|
||||
auto HEIGHT = 700;
|
||||
if (!_marketplaceWindow) {
|
||||
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
|
||||
}
|
||||
_marketplaceWindow->setVisible(true);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::openHeadModelBrowser() {
|
||||
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
|
||||
auto WIDTH = 900;
|
||||
auto HEIGHT = 700;
|
||||
if (!_marketplaceWindow) {
|
||||
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
|
||||
}
|
||||
_marketplaceWindow->setVisible(true);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::openBodyModelBrowser() {
|
||||
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
|
||||
auto WIDTH = 900;
|
||||
auto HEIGHT = 700;
|
||||
if (!_marketplaceWindow) {
|
||||
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
|
||||
}
|
||||
_marketplaceWindow->setVisible(true);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::resizeEvent(QResizeEvent *resizeEvent) {
|
||||
|
||||
// keep buttons panel at the bottom
|
||||
ui.buttonsPanel->setGeometry(0,
|
||||
size().height() - ui.buttonsPanel->height(),
|
||||
size().width(),
|
||||
ui.buttonsPanel->height());
|
||||
|
||||
// set width and height of srcollarea to match bottom panel and width
|
||||
ui.scrollArea->setGeometry(ui.scrollArea->geometry().x(), ui.scrollArea->geometry().y(),
|
||||
size().width(),
|
||||
size().height() - ui.buttonsPanel->height() - ui.scrollArea->geometry().y());
|
||||
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::loadAvatarAppearance() {
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
_useFullAvatar = myAvatar->getUseFullAvatar();
|
||||
_fullAvatarURLString = myAvatar->getFullAvatarURLFromPreferences().toString();
|
||||
_headURLString = myAvatar->getHeadURLFromPreferences().toString();
|
||||
_bodyURLString = myAvatar->getBodyURLFromPreferences().toString();
|
||||
|
||||
ui.fullAvatarURLEdit->setText(_fullAvatarURLString);
|
||||
ui.faceURLEdit->setText(_headURLString);
|
||||
ui.skeletonURLEdit->setText(_bodyURLString);
|
||||
setUseFullAvatar(_useFullAvatar);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::saveAvatarAppearance() {
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
QUrl headURL(ui.faceURLEdit->text());
|
||||
QString headURLString = headURL.toString();
|
||||
|
||||
QUrl bodyURL(ui.skeletonURLEdit->text());
|
||||
QString bodyURLString = bodyURL.toString();
|
||||
|
||||
QUrl fullAvatarURL(ui.fullAvatarURLEdit->text());
|
||||
QString fullAvatarURLString = fullAvatarURL.toString();
|
||||
|
||||
bool somethingChanged =
|
||||
_useFullAvatar != myAvatar->getUseFullAvatar() ||
|
||||
fullAvatarURLString != myAvatar->getFullAvatarURLFromPreferences().toString() ||
|
||||
headURLString != myAvatar->getHeadURLFromPreferences().toString() ||
|
||||
bodyURLString != myAvatar->getBodyURLFromPreferences().toString();
|
||||
|
||||
if (somethingChanged) {
|
||||
if (_useFullAvatar) {
|
||||
myAvatar->useFullAvatarURL(fullAvatarURL);
|
||||
} else {
|
||||
myAvatar->useHeadAndBodyURLs(headURL, bodyURL);
|
||||
}
|
||||
}
|
||||
}
|
64
interface/src/ui/AvatarAppearanceDialog.h
Normal file
64
interface/src/ui/AvatarAppearanceDialog.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// AvatarAppearanceDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 2/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AvatarAppearanceDialog_h
|
||||
#define hifi_AvatarAppearanceDialog_h
|
||||
|
||||
#include "ui_avatarAppearance.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
#include "scripting/WebWindowClass.h"
|
||||
|
||||
class AvatarAppearanceDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AvatarAppearanceDialog(QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* resizeEvent);
|
||||
|
||||
private:
|
||||
void loadAvatarAppearance();
|
||||
void saveAvatarAppearance();
|
||||
void openHeadModelBrowser();
|
||||
void openBodyModelBrowser();
|
||||
void openFullAvatarModelBrowser();
|
||||
void setUseFullAvatar(bool useFullAvatar);
|
||||
|
||||
Ui_AvatarAppearanceDialog ui;
|
||||
|
||||
bool _useFullAvatar;
|
||||
QString _headURLString;
|
||||
QString _bodyURLString;
|
||||
QString _fullAvatarURLString;
|
||||
|
||||
|
||||
QString _displayNameString;
|
||||
|
||||
WebWindowClass* _marketplaceWindow = NULL;
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
void setHeadUrl(QString modelUrl);
|
||||
void setSkeletonUrl(QString modelUrl);
|
||||
void headURLChanged(const QString& newValue, const QString& modelName);
|
||||
void bodyURLChanged(const QString& newValue, const QString& modelName);
|
||||
void fullAvatarURLChanged(const QString& newValue, const QString& modelName);
|
||||
void useSeparateBodyAndHead(bool checked);
|
||||
void useFullAvatar(bool checked);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_AvatarAppearanceDialog_h
|
|
@ -18,6 +18,7 @@
|
|||
#include "AddressBarDialog.h"
|
||||
#include "AnimationsDialog.h"
|
||||
#include "AttachmentsDialog.h"
|
||||
#include "AvatarAppearanceDialog.h"
|
||||
#include "BandwidthDialog.h"
|
||||
#include "CachesSizeDialog.h"
|
||||
#include "DiskCacheEditor.h"
|
||||
|
@ -85,6 +86,15 @@ void DialogsManager::editPreferences() {
|
|||
}
|
||||
}
|
||||
|
||||
void DialogsManager::changeAvatarAppearance() {
|
||||
if (!_avatarAppearanceDialog) {
|
||||
maybeCreateDialog(_avatarAppearanceDialog);
|
||||
_avatarAppearanceDialog->show();
|
||||
} else {
|
||||
_avatarAppearanceDialog->close();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsManager::editAttachments() {
|
||||
if (!_attachmentsDialog) {
|
||||
maybeCreateDialog(_attachmentsDialog);
|
||||
|
|
|
@ -33,6 +33,7 @@ class OctreeStatsDialog;
|
|||
class PreferencesDialog;
|
||||
class ScriptEditorWindow;
|
||||
class QMessageBox;
|
||||
class AvatarAppearanceDialog;
|
||||
|
||||
class DialogsManager : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -43,6 +44,7 @@ public:
|
|||
QPointer<HMDToolsDialog> getHMDToolsDialog() const { return _hmdToolsDialog; }
|
||||
QPointer<LodToolsDialog> getLodToolsDialog() const { return _lodToolsDialog; }
|
||||
QPointer<OctreeStatsDialog> getOctreeStatsDialog() const { return _octreeStatsDialog; }
|
||||
QPointer<PreferencesDialog> getPreferencesDialog() const { return _preferencesDialog; }
|
||||
|
||||
public slots:
|
||||
void toggleAddressBar();
|
||||
|
@ -59,6 +61,7 @@ public slots:
|
|||
void hmdTools(bool showTools);
|
||||
void showScriptEditor();
|
||||
void showIRCLink();
|
||||
void changeAvatarAppearance();
|
||||
|
||||
private slots:
|
||||
void toggleToolWindow();
|
||||
|
@ -94,6 +97,7 @@ private:
|
|||
QPointer<OctreeStatsDialog> _octreeStatsDialog;
|
||||
QPointer<PreferencesDialog> _preferencesDialog;
|
||||
QPointer<ScriptEditorWindow> _scriptEditor;
|
||||
QPointer<AvatarAppearanceDialog> _avatarAppearanceDialog;
|
||||
};
|
||||
|
||||
#endif // hifi_DialogsManager_h
|
|
@ -19,6 +19,7 @@
|
|||
#include <NetworkingConstants.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "DialogsManager.h"
|
||||
#include "MainWindow.h"
|
||||
#include "LODManager.h"
|
||||
#include "Menu.h"
|
||||
|
@ -41,30 +42,40 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) :
|
|||
ui.outputBufferSizeSpinner->setMinimum(MIN_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES);
|
||||
ui.outputBufferSizeSpinner->setMaximum(MAX_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES);
|
||||
|
||||
connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &PreferencesDialog::openHeadModelBrowser);
|
||||
connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &PreferencesDialog::openBodyModelBrowser);
|
||||
connect(ui.buttonBrowseLocation, &QPushButton::clicked, this, &PreferencesDialog::openSnapshotLocationBrowser);
|
||||
connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser);
|
||||
connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked,
|
||||
Application::getInstance(), &Application::loadDefaultScripts);
|
||||
connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, Application::getInstance(), &Application::loadDefaultScripts);
|
||||
|
||||
DialogsManager* dialogsManager = DependencyManager::get<DialogsManager>().data();
|
||||
connect(ui.buttonChangeApperance, &QPushButton::clicked, dialogsManager, &DialogsManager::changeAvatarAppearance);
|
||||
|
||||
connect(Application::getInstance(), &Application::faceURLChanged, this, &PreferencesDialog::faceURLChanged);
|
||||
connect(Application::getInstance(), &Application::skeletonURLChanged, this, &PreferencesDialog::skeletonURLChanged);
|
||||
connect(Application::getInstance(), &Application::headURLChanged, this, &PreferencesDialog::headURLChanged);
|
||||
connect(Application::getInstance(), &Application::bodyURLChanged, this, &PreferencesDialog::bodyURLChanged);
|
||||
connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged);
|
||||
|
||||
// move dialog to left side
|
||||
move(parentWidget()->geometry().topLeft());
|
||||
setFixedHeight(parentWidget()->size().height() - PREFERENCES_HEIGHT_PADDING);
|
||||
|
||||
ui.apperanceDescription->setText(DependencyManager::get<AvatarManager>()->getMyAvatar()->getModelDescription());
|
||||
|
||||
UIUtil::scaleWidgetFontSizes(this);
|
||||
}
|
||||
|
||||
void PreferencesDialog::faceURLChanged(const QString& newValue) {
|
||||
ui.faceURLEdit->setText(newValue);
|
||||
void PreferencesDialog::avatarDescriptionChanged() {
|
||||
ui.apperanceDescription->setText(DependencyManager::get<AvatarManager>()->getMyAvatar()->getModelDescription());
|
||||
}
|
||||
|
||||
void PreferencesDialog::skeletonURLChanged(const QString& newValue) {
|
||||
ui.skeletonURLEdit->setText(newValue);
|
||||
void PreferencesDialog::headURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.apperanceDescription->setText(DependencyManager::get<AvatarManager>()->getMyAvatar()->getModelDescription());
|
||||
}
|
||||
|
||||
void PreferencesDialog::bodyURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.apperanceDescription->setText(DependencyManager::get<AvatarManager>()->getMyAvatar()->getModelDescription());
|
||||
}
|
||||
|
||||
void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.apperanceDescription->setText(DependencyManager::get<AvatarManager>()->getMyAvatar()->getModelDescription());
|
||||
}
|
||||
|
||||
void PreferencesDialog::accept() {
|
||||
|
@ -74,34 +85,6 @@ void PreferencesDialog::accept() {
|
|||
_marketplaceWindow = NULL;
|
||||
}
|
||||
|
||||
void PreferencesDialog::setHeadUrl(QString modelUrl) {
|
||||
ui.faceURLEdit->setText(modelUrl);
|
||||
}
|
||||
|
||||
void PreferencesDialog::setSkeletonUrl(QString modelUrl) {
|
||||
ui.skeletonURLEdit->setText(modelUrl);
|
||||
}
|
||||
|
||||
void PreferencesDialog::openHeadModelBrowser() {
|
||||
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
|
||||
auto WIDTH = 900;
|
||||
auto HEIGHT = 700;
|
||||
if (!_marketplaceWindow) {
|
||||
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
|
||||
}
|
||||
_marketplaceWindow->setVisible(true);
|
||||
}
|
||||
|
||||
void PreferencesDialog::openBodyModelBrowser() {
|
||||
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
|
||||
auto WIDTH = 900;
|
||||
auto HEIGHT = 700;
|
||||
if (!_marketplaceWindow) {
|
||||
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
|
||||
}
|
||||
_marketplaceWindow->setVisible(true);
|
||||
}
|
||||
|
||||
void PreferencesDialog::openSnapshotLocationBrowser() {
|
||||
QString dir = QFileDialog::getExistingDirectory(this, tr("Snapshots Location"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),
|
||||
|
@ -143,12 +126,6 @@ void PreferencesDialog::loadPreferences() {
|
|||
_displayNameString = myAvatar->getDisplayName();
|
||||
ui.displayNameEdit->setText(_displayNameString);
|
||||
|
||||
_faceURLString = myAvatar->getHead()->getFaceModel().getURL().toString();
|
||||
ui.faceURLEdit->setText(_faceURLString);
|
||||
|
||||
_skeletonURLString = myAvatar->getSkeletonModel().getURL().toString();
|
||||
ui.skeletonURLEdit->setText(_skeletonURLString);
|
||||
|
||||
ui.sendDataCheckBox->setChecked(!menuInstance->isOptionChecked(MenuOption::DisableActivityLogger));
|
||||
|
||||
ui.snapshotLocationEdit->setText(Snapshot::snapshotsLocation.get());
|
||||
|
@ -208,6 +185,7 @@ void PreferencesDialog::loadPreferences() {
|
|||
void PreferencesDialog::savePreferences() {
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
bool shouldDispatchIdentityPacket = false;
|
||||
|
||||
QString displayNameStr(ui.displayNameEdit->text());
|
||||
|
@ -217,34 +195,6 @@ void PreferencesDialog::savePreferences() {
|
|||
shouldDispatchIdentityPacket = true;
|
||||
}
|
||||
|
||||
auto AVATAR_FILE_EXTENSION = ".fst";
|
||||
|
||||
QUrl faceModelURL(ui.faceURLEdit->text());
|
||||
QString faceModelURLString = faceModelURL.toString();
|
||||
if (faceModelURLString != _faceURLString) {
|
||||
if (faceModelURLString.isEmpty() || faceModelURLString.toLower().contains(AVATAR_FILE_EXTENSION)) {
|
||||
// change the faceModelURL in the profile, it will also update this user's BlendFace
|
||||
myAvatar->setFaceModelURL(faceModelURL);
|
||||
UserActivityLogger::getInstance().changedModel("head", faceModelURLString);
|
||||
shouldDispatchIdentityPacket = true;
|
||||
} else {
|
||||
qDebug() << "ERROR: Head model not FST or blank - " << faceModelURLString;
|
||||
}
|
||||
}
|
||||
|
||||
QUrl skeletonModelURL(ui.skeletonURLEdit->text());
|
||||
QString skeletonModelURLString = skeletonModelURL.toString();
|
||||
if (skeletonModelURLString != _skeletonURLString) {
|
||||
if (skeletonModelURLString.isEmpty() || skeletonModelURLString.toLower().contains(AVATAR_FILE_EXTENSION)) {
|
||||
// change the skeletonModelURL in the profile, it will also update this user's Body
|
||||
myAvatar->setSkeletonModelURL(skeletonModelURL);
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", skeletonModelURLString);
|
||||
shouldDispatchIdentityPacket = true;
|
||||
} else {
|
||||
qDebug() << "ERROR: Skeleton model not FST or blank - " << skeletonModelURLString;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldDispatchIdentityPacket) {
|
||||
myAvatar->sendIdentityPacket();
|
||||
}
|
||||
|
|
|
@ -25,31 +25,28 @@ class PreferencesDialog : public QDialog {
|
|||
public:
|
||||
PreferencesDialog(QWidget* parent = nullptr);
|
||||
|
||||
void avatarDescriptionChanged();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* resizeEvent);
|
||||
|
||||
private:
|
||||
void loadPreferences();
|
||||
void savePreferences();
|
||||
void openHeadModelBrowser();
|
||||
void openBodyModelBrowser();
|
||||
|
||||
Ui_PreferencesDialog ui;
|
||||
QString _faceURLString;
|
||||
QString _skeletonURLString;
|
||||
|
||||
QString _displayNameString;
|
||||
|
||||
WebWindowClass* _marketplaceWindow = NULL;
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
void setHeadUrl(QString modelUrl);
|
||||
void setSkeletonUrl(QString modelUrl);
|
||||
void openSnapshotLocationBrowser();
|
||||
void openScriptsLocationBrowser();
|
||||
void faceURLChanged(const QString& newValue);
|
||||
void skeletonURLChanged(const QString& newValue);
|
||||
|
||||
void headURLChanged(const QString& newValue, const QString& modelName);
|
||||
void bodyURLChanged(const QString& newValue, const QString& modelName);
|
||||
void fullAvatarURLChanged(const QString& newValue, const QString& modelName);
|
||||
};
|
||||
|
||||
#endif // hifi_PreferencesDialog_h
|
||||
|
|
471
interface/ui/avatarAppearance.ui
Normal file
471
interface/ui/avatarAppearance.ui
Normal file
|
@ -0,0 +1,471 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AvatarAppearanceDialog</class>
|
||||
<widget class="QDialog" name="AvatarAppearanceDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>350</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>13</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>-107</y>
|
||||
<width>485</width>
|
||||
<height>1550</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
|
||||
|
||||
|
||||
<item>
|
||||
<widget class="QRadioButton" name="useFullAvatar">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use single avatar with Body and Head</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_fullAvatar">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
||||
|
||||
<item>
|
||||
<widget class="QLabel" name="fullAvatarNameLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Full Avatar</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>fullAvatarURLEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_fullAvatar">
|
||||
|
||||
<item>
|
||||
<widget class="QLineEdit" name="fullAvatarURLEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_fullAvatar">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonBrowseFullAvatar">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
</layout>
|
||||
|
||||
|
||||
|
||||
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QRadioButton" name="useSeparateBodyAndHead">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use separate Body and Head avatar files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_separateParts_head">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
|
||||
|
||||
|
||||
<item>
|
||||
<widget class="QLabel" name="headNameLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Head</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
</widget>
|
||||
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="faceURLEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonBrowseHead">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_separateParts_body">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
|
||||
<item>
|
||||
<widget class="QLabel" name="bodyNameLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Body</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>skeletonURLEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_skeletonURL">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="skeletonURLEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonBrowseBody">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="buttonsPanel">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttonsHBox_2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_14">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="defaultButton">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
</ui>
|
|
@ -128,6 +128,8 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="spacing">
|
||||
|
@ -187,8 +189,9 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_appearance">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
@ -199,33 +202,47 @@
|
|||
<number>7</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="headLabel">
|
||||
<widget class="QLabel" name="appearanceLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Head</string>
|
||||
<string><html><head/><body><p>Appearance</p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>snapshotLocationEdit</cstring>
|
||||
<cstring>apperanceDescription</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_1_apperanceDescription">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="faceURLEdit"/>
|
||||
<widget class="QLineEdit" name="apperanceDescription">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<spacer name="horizontalSpacer_1_apperanceDescription">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
|
@ -241,96 +258,14 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonBrowseHead">
|
||||
<widget class="QPushButton" name="buttonChangeApperance">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="headLabel_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Body</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>skeletonURLEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="skeletonURLEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonBrowseBody">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
<string>Change</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
|
@ -342,8 +277,11 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
@ -413,6 +351,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_1">
|
||||
<property name="spacing">
|
||||
|
@ -463,6 +402,10 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -665,6 +608,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QCheckBox" name="sendDataCheckBox">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
@ -493,7 +493,7 @@ void AudioClient::start() {
|
|||
_sourceGain.initialize();
|
||||
_noiseSource.initialize();
|
||||
_toneSource.initialize();
|
||||
_sourceGain.setParameters(0.25f, 0.0f);
|
||||
_sourceGain.setParameters(0.05f, 0.0f);
|
||||
_inputGain.setParameters(1.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
@ -726,9 +726,9 @@ void AudioClient::handleAudioInput() {
|
|||
int inputSamplesRequired = (int)((float)AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio);
|
||||
|
||||
QByteArray inputByteArray = _inputDevice->readAll();
|
||||
|
||||
|
||||
// Add audio source injection if enabled
|
||||
if (!_muted && _audioSourceInjectEnabled) {
|
||||
|
||||
int16_t* inputFrameData = (int16_t*)inputByteArray.data();
|
||||
const uint32_t inputFrameCount = inputByteArray.size() / sizeof(int16_t);
|
||||
|
||||
|
@ -737,17 +737,12 @@ void AudioClient::handleAudioInput() {
|
|||
#if ENABLE_INPUT_GAIN
|
||||
_inputGain.render(_inputFrameBuffer); // input/mic gain+mute
|
||||
#endif
|
||||
// Add audio source injection if enabled
|
||||
if (_audioSourceInjectEnabled) {
|
||||
|
||||
if (_toneSourceEnabled) { // sine generator
|
||||
_toneSource.render(_inputFrameBuffer);
|
||||
}
|
||||
else if(_noiseSourceEnabled) { // pink noise generator
|
||||
_noiseSource.render(_inputFrameBuffer);
|
||||
}
|
||||
_sourceGain.render(_inputFrameBuffer); // post gain
|
||||
if (_toneSourceEnabled) { // sine generator
|
||||
_toneSource.render(_inputFrameBuffer);
|
||||
} else if(_noiseSourceEnabled) { // pink noise generator
|
||||
_noiseSource.render(_inputFrameBuffer);
|
||||
}
|
||||
_sourceGain.render(_inputFrameBuffer); // post gain
|
||||
_inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, true /*copy out*/);
|
||||
}
|
||||
|
||||
|
@ -972,8 +967,8 @@ void AudioClient::setIsStereoInput(bool isStereoInput) {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioClient::toggleAudioSourceInject() {
|
||||
_audioSourceInjectEnabled = !_audioSourceInjectEnabled;
|
||||
void AudioClient::enableAudioSourceInject(bool enable) {
|
||||
_audioSourceInjectEnabled = enable;
|
||||
}
|
||||
|
||||
void AudioClient::selectAudioSourcePinkNoise() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// AudioClient.h
|
||||
// interface/src
|
||||
// libraries/audio-client/src
|
||||
//
|
||||
// Created by Stephen Birarda on 1/22/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
|
@ -143,9 +143,9 @@ public slots:
|
|||
void audioMixerKilled();
|
||||
void toggleMute();
|
||||
|
||||
void toggleAudioSourceInject();
|
||||
void selectAudioSourcePinkNoise();
|
||||
void selectAudioSourceSine440();
|
||||
virtual void enableAudioSourceInject(bool enable);
|
||||
virtual void selectAudioSourcePinkNoise();
|
||||
virtual void selectAudioSourceSine440();
|
||||
|
||||
void toggleAudioNoiseReduction() { _isNoiseGateEnabled = !_isNoiseGateEnabled; }
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@ public:
|
|||
|
||||
public slots:
|
||||
virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) = 0;
|
||||
|
||||
virtual void enableAudioSourceInject(bool enable) = 0;
|
||||
virtual void selectAudioSourcePinkNoise() = 0;
|
||||
virtual void selectAudioSourceSine440() = 0;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(AbstractAudioInterface*)
|
||||
|
|
|
@ -60,6 +60,7 @@ AvatarData::AvatarData() :
|
|||
_owningAvatarMixer(),
|
||||
_lastUpdateTimer(),
|
||||
_velocity(0.0f),
|
||||
_targetVelocity(0.0f),
|
||||
_localAABox(DEFAULT_LOCAL_AABOX_CORNER, DEFAULT_LOCAL_AABOX_SCALE)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -103,6 +103,8 @@ const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000;
|
|||
|
||||
const QUrl DEFAULT_HEAD_MODEL_URL = QUrl("http://public.highfidelity.io/models/heads/defaultAvatar_head.fst");
|
||||
const QUrl DEFAULT_BODY_MODEL_URL = QUrl("http://public.highfidelity.io/models/skeletons/defaultAvatar_body.fst");
|
||||
const QUrl DEFAULT_FULL_AVATAR_MODEL_URL = QUrl("http://public.highfidelity.io/marketplace/contents/029db3d4-da2c-4cb2-9c08-b9612ba576f5/02949063e7c4aed42ad9d1a58461f56d.fst");
|
||||
|
||||
|
||||
// Where one's own Avatar begins in the world (will be overwritten if avatar data file is found).
|
||||
// This is the start location in the Sandbox (xyz: 6270, 211, 6000).
|
||||
|
@ -294,6 +296,7 @@ public:
|
|||
|
||||
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
|
||||
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
|
||||
glm::vec3 getTargetVelocity() const { return _targetVelocity; }
|
||||
|
||||
public slots:
|
||||
void sendAvatarDataPacket();
|
||||
|
@ -384,6 +387,7 @@ protected:
|
|||
void changeReferential(Referential* ref);
|
||||
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _targetVelocity;
|
||||
|
||||
AABox _localAABox;
|
||||
|
||||
|
|
|
@ -274,47 +274,49 @@ void RenderableModelEntityItem::setCollisionModelURL(const QString& url) {
|
|||
}
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::hasCollisionModel() const {
|
||||
if (_model) {
|
||||
return ! _model->getCollisionURL().isEmpty();
|
||||
} else {
|
||||
return !_collisionModelURL.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
const QString& RenderableModelEntityItem::getCollisionModelURL() const {
|
||||
// assert (!_model || _collisionModelURL == _model->getCollisionURL().toString());
|
||||
return _collisionModelURL;
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::isReadyToComputeShape() {
|
||||
ShapeType type = getShapeType();
|
||||
if (type == SHAPE_TYPE_COMPOUND) {
|
||||
|
||||
if (!_model) {
|
||||
return false; // hmm...
|
||||
if (!_model) {
|
||||
return false; // hmm...
|
||||
}
|
||||
|
||||
assert(!_model->getCollisionURL().isEmpty());
|
||||
|
||||
if (_model->getURL().isEmpty()) {
|
||||
// we need a render geometry with a scale to proceed, so give up.
|
||||
return false;
|
||||
}
|
||||
|
||||
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
|
||||
const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();
|
||||
|
||||
if ((! collisionNetworkGeometry.isNull() && collisionNetworkGeometry->isLoadedWithTextures()) &&
|
||||
(! renderNetworkGeometry.isNull() && renderNetworkGeometry->isLoadedWithTextures())) {
|
||||
// we have both URLs AND both geometries AND they are both fully loaded.
|
||||
return true;
|
||||
}
|
||||
|
||||
// the model is still being downloaded.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_model->getCollisionURL().isEmpty()) {
|
||||
// no collision-model url, so we're ready to compute a shape (of type None).
|
||||
return true;
|
||||
}
|
||||
|
||||
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
|
||||
if (! collisionNetworkGeometry.isNull() && collisionNetworkGeometry->isLoadedWithTextures()) {
|
||||
// we have a _collisionModelURL AND a collisionNetworkGeometry AND it's fully loaded.
|
||||
return true;
|
||||
}
|
||||
|
||||
// the model is still being downloaded.
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||
if (_model->getCollisionURL().isEmpty()) {
|
||||
info.setParams(getShapeType(), 0.5f * getDimensions());
|
||||
ShapeType type = getShapeType();
|
||||
if (type != SHAPE_TYPE_COMPOUND) {
|
||||
ModelEntityItem::computeShapeInfo(info);
|
||||
info.setParams(type, 0.5f * getDimensions());
|
||||
} else {
|
||||
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
|
||||
const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry();
|
||||
|
||||
// should never fall in here when collision model not fully loaded
|
||||
// hence we assert collisionNetworkGeometry is not NULL
|
||||
assert(!collisionNetworkGeometry.isNull());
|
||||
|
||||
const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry();
|
||||
const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();
|
||||
const FBXGeometry& renderGeometry = renderNetworkGeometry->getFBXGeometry();
|
||||
|
||||
|
@ -408,18 +410,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
}
|
||||
|
||||
glm::vec3 collisionModelDimensions = box.getDimensions();
|
||||
info.setParams(getShapeType(), collisionModelDimensions, _collisionModelURL);
|
||||
info.setParams(type, collisionModelDimensions, _collisionModelURL);
|
||||
info.setConvexHulls(_points);
|
||||
}
|
||||
}
|
||||
|
||||
ShapeType RenderableModelEntityItem::getShapeType() const {
|
||||
// XXX make hull an option in edit.js ?
|
||||
if (!_model || _model->getCollisionURL().isEmpty()) {
|
||||
return _shapeType;
|
||||
} else if (_points.size() == 1) {
|
||||
return SHAPE_TYPE_CONVEX_HULL;
|
||||
} else {
|
||||
return SHAPE_TYPE_COMPOUND;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,12 +53,9 @@ public:
|
|||
bool needsToCallUpdate() const;
|
||||
|
||||
virtual void setCollisionModelURL(const QString& url);
|
||||
virtual bool hasCollisionModel() const;
|
||||
virtual const QString& getCollisionModelURL() const;
|
||||
|
||||
bool isReadyToComputeShape();
|
||||
void computeShapeInfo(ShapeInfo& info);
|
||||
ShapeType getShapeType() const;
|
||||
|
||||
private:
|
||||
void remapTextures();
|
||||
|
|
|
@ -192,7 +192,7 @@ void buildStringToShapeTypeLookup() {
|
|||
stringToShapeTypeLookup["box"] = SHAPE_TYPE_BOX;
|
||||
stringToShapeTypeLookup["sphere"] = SHAPE_TYPE_SPHERE;
|
||||
stringToShapeTypeLookup["ellipsoid"] = SHAPE_TYPE_ELLIPSOID;
|
||||
stringToShapeTypeLookup["convex-hull"] = SHAPE_TYPE_CONVEX_HULL;
|
||||
stringToShapeTypeLookup["convex-hull"] = SHAPE_TYPE_COMPOUND;
|
||||
stringToShapeTypeLookup["plane"] = SHAPE_TYPE_PLANE;
|
||||
stringToShapeTypeLookup["compound"] = SHAPE_TYPE_COMPOUND;
|
||||
stringToShapeTypeLookup["capsule-x"] = SHAPE_TYPE_CAPSULE_X;
|
||||
|
|
|
@ -276,16 +276,36 @@ void ModelEntityItem::debugDump() const {
|
|||
}
|
||||
|
||||
void ModelEntityItem::updateShapeType(ShapeType type) {
|
||||
// BEGIN_TEMPORARY_WORKAROUND
|
||||
// we have allowed inconsistent ShapeType's to be stored in SVO files in the past (this was a bug)
|
||||
// but we are now enforcing the entity properties to be consistent. To make the possible we're
|
||||
// introducing a temporary workaround: we will ignore ShapeType updates that conflict with the
|
||||
// _collisionModelURL.
|
||||
if (hasCollisionModel()) {
|
||||
type = SHAPE_TYPE_COMPOUND;
|
||||
}
|
||||
// END_TEMPORARY_WORKAROUND
|
||||
|
||||
if (type != _shapeType) {
|
||||
_shapeType = type;
|
||||
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
ShapeType ModelEntityItem::getShapeType() const {
|
||||
if (_shapeType == SHAPE_TYPE_COMPOUND) {
|
||||
return hasCollisionModel() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
|
||||
} else {
|
||||
return _shapeType;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelEntityItem::setCollisionModelURL(const QString& url) {
|
||||
if (_collisionModelURL != url) {
|
||||
_collisionModelURL = url;
|
||||
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
|
||||
_shapeType = _collisionModelURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
virtual void debugDump() const;
|
||||
|
||||
void updateShapeType(ShapeType type);
|
||||
virtual ShapeType getShapeType() const { return _shapeType; }
|
||||
virtual ShapeType getShapeType() const;
|
||||
|
||||
// TODO: Move these to subclasses, or other appropriate abstraction
|
||||
// getters/setters applicable to models and particles
|
||||
|
@ -63,7 +63,7 @@ public:
|
|||
const QString& getModelURL() const { return _modelURL; }
|
||||
|
||||
static const QString DEFAULT_COLLISION_MODEL_URL;
|
||||
virtual const QString& getCollisionModelURL() const { return _collisionModelURL; }
|
||||
const QString& getCollisionModelURL() const { return _collisionModelURL; }
|
||||
|
||||
bool hasAnimation() const { return !_animationURL.isEmpty(); }
|
||||
static const QString DEFAULT_ANIMATION_URL;
|
||||
|
|
|
@ -10,6 +10,13 @@
|
|||
//
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "FSTReader.h"
|
||||
|
||||
|
@ -169,3 +176,17 @@ FSTReader::ModelType FSTReader::predictModelType(const QVariantHash& mapping) {
|
|||
|
||||
return ENTITY_MODEL;
|
||||
}
|
||||
|
||||
QVariantHash FSTReader::downloadMapping(const QString& url) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
qDebug() << "Downloading avatar file at " << url;
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
QByteArray fstContents = reply->readAll();
|
||||
delete reply;
|
||||
return FSTReader::readMapping(fstContents);
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
|
||||
static QString getNameFromType(ModelType modelType);
|
||||
static FSTReader::ModelType getTypeFromName(const QString& name);
|
||||
static QVariantHash downloadMapping(const QString& url);
|
||||
|
||||
private:
|
||||
static void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it);
|
||||
|
|
|
@ -25,7 +25,8 @@ Batch::Batch() :
|
|||
_textures(),
|
||||
_streamFormats(),
|
||||
_transforms(),
|
||||
_pipelines()
|
||||
_pipelines(),
|
||||
_framebuffers()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -41,7 +42,8 @@ void Batch::clear() {
|
|||
_textures.clear();
|
||||
_streamFormats.clear();
|
||||
_transforms.clear();
|
||||
_pipelines.clear();
|
||||
_pipelines.clear();
|
||||
_framebuffers.clear();
|
||||
}
|
||||
|
||||
uint32 Batch::cacheData(uint32 size, const void* data) {
|
||||
|
@ -186,3 +188,10 @@ void Batch::setUniformTexture(uint32 slot, const TextureView& view) {
|
|||
setUniformTexture(slot, view._texture);
|
||||
}
|
||||
|
||||
void Batch::setFramebuffer(const FramebufferPointer& framebuffer) {
|
||||
ADD_COMMAND(setUniformTexture);
|
||||
|
||||
_params.push_back(_framebuffers.cache(framebuffer));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
#include "Pipeline.h"
|
||||
|
||||
#include "Framebuffer.h"
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
#include "nvToolsExt.h"
|
||||
class ProfileRange {
|
||||
|
@ -112,6 +114,8 @@ public:
|
|||
void setUniformTexture(uint32 slot, const TexturePointer& view);
|
||||
void setUniformTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView
|
||||
|
||||
// Framebuffer Stage
|
||||
void setFramebuffer(const FramebufferPointer& framebuffer);
|
||||
|
||||
// TODO: As long as we have gl calls explicitely issued from interface
|
||||
// code, we need to be able to record and batch these calls. THe long
|
||||
|
@ -170,6 +174,8 @@ public:
|
|||
COMMAND_setUniformBuffer,
|
||||
COMMAND_setUniformTexture,
|
||||
|
||||
COMMAND_setFramebuffer,
|
||||
|
||||
// TODO: As long as we have gl calls explicitely issued from interface
|
||||
// code, we need to be able to record and batch these calls. THe long
|
||||
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
||||
|
@ -266,6 +272,7 @@ public:
|
|||
typedef Cache<Stream::FormatPointer>::Vector StreamFormatCaches;
|
||||
typedef Cache<Transform>::Vector TransformCaches;
|
||||
typedef Cache<PipelinePointer>::Vector PipelineCaches;
|
||||
typedef Cache<FramebufferPointer>::Vector FramebufferCaches;
|
||||
|
||||
// Cache Data in a byte array if too big to fit in Param
|
||||
// FOr example Mat4s are going there
|
||||
|
@ -289,6 +296,7 @@ public:
|
|||
StreamFormatCaches _streamFormats;
|
||||
TransformCaches _transforms;
|
||||
PipelineCaches _pipelines;
|
||||
FramebufferCaches _framebuffers;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
#include "Resource.h"
|
||||
#include "Texture.h"
|
||||
#include "Shader.h"
|
||||
#include "Pipeline.h"
|
||||
#include "Framebuffer.h"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
|
@ -47,8 +47,8 @@ public:
|
|||
};
|
||||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Buffer& buffer, T* bo) {
|
||||
buffer.setGPUObject(bo);
|
||||
static void setGPUObject(const Buffer& buffer, T* object) {
|
||||
buffer.setGPUObject(object);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Buffer& buffer) {
|
||||
|
@ -56,8 +56,8 @@ public:
|
|||
}
|
||||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Texture& texture, T* to) {
|
||||
texture.setGPUObject(to);
|
||||
static void setGPUObject(const Texture& texture, T* object) {
|
||||
texture.setGPUObject(object);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Texture& texture) {
|
||||
|
@ -65,8 +65,8 @@ public:
|
|||
}
|
||||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Shader& shader, T* so) {
|
||||
shader.setGPUObject(so);
|
||||
static void setGPUObject(const Shader& shader, T* object) {
|
||||
shader.setGPUObject(object);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Shader& shader) {
|
||||
|
@ -74,8 +74,8 @@ public:
|
|||
}
|
||||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Pipeline& pipeline, T* po) {
|
||||
pipeline.setGPUObject(po);
|
||||
static void setGPUObject(const Pipeline& pipeline, T* object) {
|
||||
pipeline.setGPUObject(object);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Pipeline& pipeline) {
|
||||
|
@ -83,14 +83,23 @@ public:
|
|||
}
|
||||
|
||||
template< typename T >
|
||||
static void setGPUObject(const State& state, T* so) {
|
||||
state.setGPUObject(so);
|
||||
static void setGPUObject(const State& state, T* object) {
|
||||
state.setGPUObject(object);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const State& state) {
|
||||
return reinterpret_cast<T*>(state.getGPUObject());
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Framebuffer& framebuffer, T* object) {
|
||||
framebuffer.setGPUObject(object);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Framebuffer& framebuffer) {
|
||||
return reinterpret_cast<T*>(framebuffer.getGPUObject());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
|
|
@ -34,6 +34,8 @@ typedef glm::mat3 Mat3;
|
|||
typedef glm::vec4 Vec4;
|
||||
typedef glm::vec3 Vec3;
|
||||
typedef glm::vec2 Vec2;
|
||||
typedef glm::ivec2 Vec2i;
|
||||
typedef glm::uvec2 Vec2u;
|
||||
|
||||
// Description of a scalar type
|
||||
enum Type {
|
||||
|
@ -118,7 +120,8 @@ enum Semantic {
|
|||
INDEX, //used by index buffer of a mesh
|
||||
PART, // used by part buffer of a mesh
|
||||
|
||||
DEPTH, // Depth buffer
|
||||
DEPTH, // Depth only buffer
|
||||
STENCIL, // Stencil only buffer
|
||||
DEPTH_STENCIL, // Depth Stencil buffer
|
||||
|
||||
SRGB,
|
||||
|
@ -171,12 +174,28 @@ public:
|
|||
return getRaw() != right.getRaw();
|
||||
}
|
||||
|
||||
static const Element COLOR_RGBA_32;
|
||||
|
||||
protected:
|
||||
uint8 _semantic;
|
||||
uint8 _dimension : 4;
|
||||
uint8 _type : 4;
|
||||
};
|
||||
|
||||
|
||||
enum ComparisonFunction {
|
||||
NEVER = 0,
|
||||
LESS,
|
||||
EQUAL,
|
||||
LESS_EQUAL,
|
||||
GREATER,
|
||||
NOT_EQUAL,
|
||||
GREATER_EQUAL,
|
||||
ALWAYS,
|
||||
|
||||
NUM_COMPARISON_FUNCS,
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
279
libraries/gpu/src/gpu/Framebuffer.cpp
Executable file
279
libraries/gpu/src/gpu/Framebuffer.cpp
Executable file
|
@ -0,0 +1,279 @@
|
|||
//
|
||||
// Framebuffer.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 4/12/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Framebuffer.h"
|
||||
#include <math.h>
|
||||
#include <QDebug>
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
Framebuffer::~Framebuffer() {
|
||||
}
|
||||
|
||||
Framebuffer* Framebuffer::create() {
|
||||
auto framebuffer = new Framebuffer();
|
||||
framebuffer->_renderBuffers.resize(MAX_NUM_RENDER_BUFFERS);
|
||||
return framebuffer;
|
||||
}
|
||||
|
||||
|
||||
Framebuffer* Framebuffer::create( const Format& colorBufferFormat, uint16 width, uint16 height) {
|
||||
auto framebuffer = Framebuffer::create();
|
||||
|
||||
auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
|
||||
|
||||
framebuffer->setRenderBuffer(0, colorTexture);
|
||||
|
||||
return framebuffer;
|
||||
}
|
||||
|
||||
Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height) {
|
||||
auto framebuffer = Framebuffer::create();
|
||||
|
||||
auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
|
||||
auto depthTexture = TexturePointer(Texture::create2D(depthStencilBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
|
||||
|
||||
framebuffer->setRenderBuffer(0, colorTexture);
|
||||
framebuffer->setDepthStencilBuffer(depthTexture, depthStencilBufferFormat);
|
||||
|
||||
return framebuffer;
|
||||
}
|
||||
|
||||
Framebuffer* Framebuffer::createShadowmap(uint16 width) {
|
||||
auto framebuffer = Framebuffer::create();
|
||||
auto depthTexture = TexturePointer(Texture::create2D(Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH), width, width));
|
||||
|
||||
Sampler::Desc samplerDesc;
|
||||
samplerDesc._borderColor = glm::vec4(1.0f);
|
||||
samplerDesc._wrapModeU = Sampler::WRAP_BORDER;
|
||||
samplerDesc._wrapModeV = Sampler::WRAP_BORDER;
|
||||
samplerDesc._filter = Sampler::FILTER_MIN_MAG_LINEAR;
|
||||
samplerDesc._comparisonFunc = LESS_EQUAL;
|
||||
|
||||
depthTexture->setSampler(Sampler(samplerDesc));
|
||||
|
||||
framebuffer->setDepthStencilBuffer(depthTexture, Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH));
|
||||
|
||||
return framebuffer;
|
||||
}
|
||||
|
||||
bool Framebuffer::isSwapchain() const {
|
||||
return _swapchain != 0;
|
||||
}
|
||||
|
||||
uint32 Framebuffer::getFrameCount() const {
|
||||
if (_swapchain) {
|
||||
return _swapchain->getFrameCount();
|
||||
} else {
|
||||
return _frameCount;
|
||||
}
|
||||
}
|
||||
|
||||
bool Framebuffer::validateTargetCompatibility(const Texture& texture, uint32 subresource) const {
|
||||
if (texture.getType() == Texture::TEX_1D) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isEmpty()) {
|
||||
return true;
|
||||
} else {
|
||||
if ((texture.getWidth() == getWidth()) &&
|
||||
(texture.getHeight() == getHeight()) &&
|
||||
(texture.getNumSamples() == getNumSamples())) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Framebuffer::updateSize(const TexturePointer& texture) {
|
||||
if (!isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (texture) {
|
||||
_width = texture->getWidth();
|
||||
_height = texture->getHeight();
|
||||
_numSamples = texture->getNumSamples();
|
||||
} else {
|
||||
_width = _height = _numSamples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Framebuffer::resize(uint16 width, uint16 height, uint16 numSamples) {
|
||||
if (width && height && numSamples && !isEmpty() && !isSwapchain()) {
|
||||
if ((width != _width) || (height != _height) || (numSamples != _numSamples)) {
|
||||
for (uint32 i = 0; i < _renderBuffers.size(); ++i) {
|
||||
if (_renderBuffers[i]) {
|
||||
_renderBuffers[i]._texture->resize2D(width, height, numSamples);
|
||||
_numSamples = _renderBuffers[i]._texture->getNumSamples();
|
||||
}
|
||||
}
|
||||
|
||||
if (_depthStencilBuffer) {
|
||||
_depthStencilBuffer._texture->resize2D(width, height, numSamples);
|
||||
_numSamples = _depthStencilBuffer._texture->getNumSamples();
|
||||
}
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
// _numSamples = numSamples;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16 Framebuffer::getWidth() const {
|
||||
if (isSwapchain()) {
|
||||
return getSwapchain()->getWidth();
|
||||
} else {
|
||||
return _width;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 Framebuffer::getHeight() const {
|
||||
if (isSwapchain()) {
|
||||
return getSwapchain()->getHeight();
|
||||
} else {
|
||||
return _height;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 Framebuffer::getNumSamples() const {
|
||||
if (isSwapchain()) {
|
||||
return getSwapchain()->getNumSamples();
|
||||
} else {
|
||||
return _numSamples;
|
||||
}
|
||||
}
|
||||
|
||||
// Render buffers
|
||||
int Framebuffer::setRenderBuffer(uint32 slot, const TexturePointer& texture, uint32 subresource) {
|
||||
if (isSwapchain()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check for the slot
|
||||
if (slot >= getMaxNumRenderBuffers()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check for the compatibility of size
|
||||
if (texture) {
|
||||
if (!validateTargetCompatibility(*texture, subresource)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
updateSize(texture);
|
||||
|
||||
// assign the new one
|
||||
_renderBuffers[slot] = TextureView(texture, subresource);
|
||||
|
||||
// update the mask
|
||||
int mask = (1<<slot);
|
||||
_bufferMask = (_bufferMask & ~(mask));
|
||||
if (texture) {
|
||||
_bufferMask |= mask;
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
void Framebuffer::removeRenderBuffers() {
|
||||
if (isSwapchain()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_bufferMask = _bufferMask & BUFFER_DEPTHSTENCIL;
|
||||
|
||||
for (auto renderBuffer : _renderBuffers) {
|
||||
renderBuffer._texture.reset();
|
||||
}
|
||||
|
||||
updateSize(TexturePointer(nullptr));
|
||||
}
|
||||
|
||||
|
||||
uint32 Framebuffer::getNumRenderBuffers() const {
|
||||
uint32 nb = 0;
|
||||
for (auto i : _renderBuffers) {
|
||||
nb += (!i);
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
|
||||
TexturePointer Framebuffer::getRenderBuffer(uint32 slot) const {
|
||||
if (!isSwapchain() && (slot < getMaxNumRenderBuffers())) {
|
||||
return _renderBuffers[slot]._texture;
|
||||
} else {
|
||||
return TexturePointer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint32 Framebuffer::getRenderBufferSubresource(uint32 slot) const {
|
||||
if (!isSwapchain() && (slot < getMaxNumRenderBuffers())) {
|
||||
return _renderBuffers[slot]._subresource;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) {
|
||||
if (isSwapchain()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for the compatibility of size
|
||||
if (texture) {
|
||||
if (!validateTargetCompatibility(*texture)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
updateSize(texture);
|
||||
|
||||
// assign the new one
|
||||
_depthStencilBuffer = TextureView(texture, subresource, format);
|
||||
|
||||
_bufferMask = ( _bufferMask & ~BUFFER_DEPTHSTENCIL);
|
||||
if (texture) {
|
||||
_bufferMask |= BUFFER_DEPTHSTENCIL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TexturePointer Framebuffer::getDepthStencilBuffer() const {
|
||||
if (isSwapchain()) {
|
||||
return TexturePointer();
|
||||
} else {
|
||||
return _depthStencilBuffer._texture;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Framebuffer::getDepthStencilBufferSubresource() const {
|
||||
if (isSwapchain()) {
|
||||
return 0;
|
||||
} else {
|
||||
return _depthStencilBuffer._subresource;
|
||||
}
|
||||
}
|
||||
|
||||
Format Framebuffer::getDepthStencilBufferFormat() const {
|
||||
if (isSwapchain()) {
|
||||
// return getSwapchain()->getDepthStencilBufferFormat();
|
||||
return _depthStencilBuffer._element;
|
||||
} else {
|
||||
return _depthStencilBuffer._element;
|
||||
}
|
||||
}
|
164
libraries/gpu/src/gpu/Framebuffer.h
Executable file
164
libraries/gpu/src/gpu/Framebuffer.h
Executable file
|
@ -0,0 +1,164 @@
|
|||
//
|
||||
// Framebuffer.h
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 4/12/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_gpu_Framebuffer_h
|
||||
#define hifi_gpu_Framebuffer_h
|
||||
|
||||
#include "Texture.h"
|
||||
#include <memory>
|
||||
|
||||
namespace gpu {
|
||||
|
||||
typedef Element Format;
|
||||
|
||||
class Swapchain {
|
||||
public:
|
||||
// Properties
|
||||
uint16 getWidth() const { return _width; }
|
||||
uint16 getHeight() const { return _height; }
|
||||
uint16 getNumSamples() const { return _numSamples; }
|
||||
|
||||
bool hasDepthStencil() const { return _hasDepthStencil; }
|
||||
bool isFullscreen() const { return _isFullscreen; }
|
||||
|
||||
uint32 getSwapInterval() const { return _swapInterval; }
|
||||
|
||||
bool isStereo() const { return _isStereo; }
|
||||
|
||||
uint32 getFrameCount() const { return _frameCount; }
|
||||
|
||||
// Pure interface
|
||||
void setSwapInterval(uint32 interval);
|
||||
|
||||
void resize(uint16 width, uint16 height);
|
||||
void setFullscreen(bool fullscreen);
|
||||
|
||||
Swapchain() {}
|
||||
Swapchain(const Swapchain& swapchain) {}
|
||||
virtual ~Swapchain() {}
|
||||
|
||||
protected:
|
||||
mutable uint32 _frameCount = 0;
|
||||
|
||||
Format _colorFormat;
|
||||
uint16 _width = 1;
|
||||
uint16 _height = 1;
|
||||
uint16 _numSamples = 1;
|
||||
uint16 _swapInterval = 0;
|
||||
|
||||
bool _hasDepthStencil = false;
|
||||
bool _isFullscreen = false;
|
||||
bool _isStereo = false;
|
||||
|
||||
// Non exposed
|
||||
|
||||
friend class Framebuffer;
|
||||
};
|
||||
typedef std::shared_ptr<Swapchain> SwapchainPointer;
|
||||
|
||||
|
||||
class Framebuffer {
|
||||
public:
|
||||
enum BufferMask {
|
||||
BUFFER_COLOR0 = 1,
|
||||
BUFFER_COLOR1 = 2,
|
||||
BUFFER_COLOR2 = 4,
|
||||
BUFFER_COLOR3 = 8,
|
||||
BUFFER_COLOR4 = 16,
|
||||
BUFFER_COLOR5 = 32,
|
||||
BUFFER_COLOR6 = 64,
|
||||
BUFFER_COLOR7 = 128,
|
||||
BUFFER_COLORS = 0x000000FF,
|
||||
|
||||
BUFFER_DEPTH = 0x40000000,
|
||||
BUFFER_STENCIL = 0x80000000,
|
||||
BUFFER_DEPTHSTENCIL = 0xC0000000,
|
||||
};
|
||||
|
||||
~Framebuffer();
|
||||
|
||||
static Framebuffer* create(const SwapchainPointer& swapchain);
|
||||
static Framebuffer* create();
|
||||
static Framebuffer* create(const Format& colorBufferFormat, uint16 width, uint16 height);
|
||||
static Framebuffer* create(const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height);
|
||||
static Framebuffer* createShadowmap(uint16 width);
|
||||
|
||||
bool isSwapchain() const;
|
||||
SwapchainPointer getSwapchain() const { return _swapchain; }
|
||||
|
||||
uint32 getFrameCount() const;
|
||||
|
||||
// Render buffers
|
||||
void removeRenderBuffers();
|
||||
uint32 getNumRenderBuffers() const;
|
||||
const TextureViews& getRenderBuffers() const { return _renderBuffers; }
|
||||
|
||||
int32 setRenderBuffer(uint32 slot, const TexturePointer& texture, uint32 subresource = 0);
|
||||
TexturePointer getRenderBuffer(uint32 slot) const;
|
||||
uint32 getRenderBufferSubresource(uint32 slot) const;
|
||||
|
||||
bool setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0);
|
||||
TexturePointer getDepthStencilBuffer() const;
|
||||
uint32 getDepthStencilBufferSubresource() const;
|
||||
Format getDepthStencilBufferFormat() const;
|
||||
|
||||
|
||||
// Properties
|
||||
uint32 getBufferMask() const { return _bufferMask; }
|
||||
bool isEmpty() const { return (_bufferMask == 0); }
|
||||
bool hasColor() const { return (getBufferMask() & BUFFER_COLORS); }
|
||||
bool hasDepthStencil() const { return (getBufferMask() & BUFFER_DEPTHSTENCIL); }
|
||||
|
||||
bool validateTargetCompatibility(const Texture& texture, uint32 subresource = 0) const;
|
||||
|
||||
Vec2u getSize() const { return Vec2u(getWidth(), getHeight()); }
|
||||
uint16 getWidth() const;
|
||||
uint16 getHeight() const;
|
||||
uint16 getNumSamples() const;
|
||||
|
||||
float getAspectRatio() const { return getWidth() / (float) getHeight() ; }
|
||||
|
||||
// If not a swapchain canvas, resize can resize all the render buffers and depth stencil attached in one call
|
||||
void resize( uint16 width, uint16 height, uint16 samples = 1 );
|
||||
|
||||
static const uint32 MAX_NUM_RENDER_BUFFERS = 8;
|
||||
static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; }
|
||||
|
||||
protected:
|
||||
SwapchainPointer _swapchain;
|
||||
|
||||
TextureViews _renderBuffers;
|
||||
TextureView _depthStencilBuffer;
|
||||
|
||||
uint32 _bufferMask = 0;
|
||||
|
||||
uint32 _frameCount = 0;
|
||||
|
||||
uint16 _width = 0;
|
||||
uint16 _height = 0;
|
||||
uint16 _numSamples = 0;
|
||||
|
||||
void updateSize(const TexturePointer& texture);
|
||||
|
||||
// Non exposed
|
||||
Framebuffer(const Framebuffer& framebuffer) {}
|
||||
Framebuffer() {}
|
||||
|
||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
friend class Backend;
|
||||
};
|
||||
typedef std::shared_ptr<Framebuffer> FramebufferPointer;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -32,6 +32,9 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::GLBackend::do_setUniformBuffer),
|
||||
(&::gpu::GLBackend::do_setUniformTexture),
|
||||
|
||||
(&::gpu::GLBackend::do_setFramebuffer),
|
||||
|
||||
|
||||
(&::gpu::GLBackend::do_glEnable),
|
||||
(&::gpu::GLBackend::do_glDisable),
|
||||
|
||||
|
@ -67,7 +70,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
GLBackend::GLBackend() :
|
||||
_input(),
|
||||
_transform(),
|
||||
_pipeline()
|
||||
_pipeline(),
|
||||
_output()
|
||||
{
|
||||
initTransform();
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
Stamp _storageStamp;
|
||||
Stamp _contentStamp;
|
||||
GLuint _texture;
|
||||
GLenum _target;
|
||||
GLuint _size;
|
||||
|
||||
GLTexture();
|
||||
|
@ -61,6 +62,9 @@ public:
|
|||
static GLTexture* syncGPUObject(const Texture& texture);
|
||||
static GLuint getTextureID(const TexturePointer& texture);
|
||||
|
||||
// very specific for now
|
||||
static void syncSampler(const Sampler& sampler, Texture::Type type, GLTexture* object);
|
||||
|
||||
class GLShader : public GPUObject {
|
||||
public:
|
||||
GLuint _shader;
|
||||
|
@ -133,14 +137,25 @@ public:
|
|||
|
||||
class GLPipeline : public GPUObject {
|
||||
public:
|
||||
GLShader* _program;
|
||||
GLState* _state;
|
||||
GLShader* _program = 0;
|
||||
GLState* _state = 0;
|
||||
|
||||
GLPipeline();
|
||||
~GLPipeline();
|
||||
};
|
||||
static GLPipeline* syncGPUObject(const Pipeline& pipeline);
|
||||
|
||||
|
||||
class GLFramebuffer : public GPUObject {
|
||||
public:
|
||||
GLuint _fbo = 0;
|
||||
|
||||
GLFramebuffer();
|
||||
~GLFramebuffer();
|
||||
};
|
||||
static GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer);
|
||||
static GLuint getFramebufferID(const FramebufferPointer& framebuffer);
|
||||
|
||||
static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
|
||||
static const int MAX_NUM_INPUT_BUFFERS = 16;
|
||||
|
||||
|
@ -276,8 +291,8 @@ protected:
|
|||
State::Signature _stateSignatureCache;
|
||||
|
||||
GLState* _state;
|
||||
bool _invalidState;
|
||||
bool _needStateSync;
|
||||
bool _invalidState = false;
|
||||
bool _needStateSync = true;
|
||||
|
||||
PipelineStageState() :
|
||||
_pipeline(),
|
||||
|
@ -291,6 +306,16 @@ protected:
|
|||
{}
|
||||
} _pipeline;
|
||||
|
||||
// Output stage
|
||||
void do_setFramebuffer(Batch& batch, uint32 paramOffset);
|
||||
|
||||
struct OutputStageState {
|
||||
|
||||
FramebufferPointer _framebuffer = nullptr;
|
||||
|
||||
OutputStageState() {}
|
||||
} _output;
|
||||
|
||||
// TODO: As long as we have gl calls explicitely issued from interface
|
||||
// code, we need to be able to record and batch these calls. THe long
|
||||
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
||||
|
|
157
libraries/gpu/src/gpu/GLBackendOutput.cpp
Executable file
157
libraries/gpu/src/gpu/GLBackendOutput.cpp
Executable file
|
@ -0,0 +1,157 @@
|
|||
//
|
||||
// GLBackendTexture.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 1/19/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GPULogging.h"
|
||||
#include "GLBackendShared.h"
|
||||
|
||||
|
||||
GLBackend::GLFramebuffer::GLFramebuffer() {}
|
||||
|
||||
GLBackend::GLFramebuffer::~GLFramebuffer() {
|
||||
if (_fbo != 0) {
|
||||
glDeleteFramebuffers(1, &_fbo);
|
||||
}
|
||||
}
|
||||
|
||||
GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffer) {
|
||||
GLFramebuffer* object = Backend::getGPUObject<GLBackend::GLFramebuffer>(framebuffer);
|
||||
|
||||
// If GPU object already created and in sync
|
||||
bool needUpdate = false;
|
||||
if (object) {
|
||||
return object;
|
||||
} else if (framebuffer.isEmpty()) {
|
||||
// NO framebuffer definition yet so let's avoid thinking
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// need to have a gpu object?
|
||||
if (!object) {
|
||||
GLuint fbo;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
unsigned int nbColorBuffers = 0;
|
||||
GLenum colorBuffers[16];
|
||||
if (framebuffer.hasColor()) {
|
||||
static const GLenum colorAttachments[] = {
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_COLOR_ATTACHMENT1,
|
||||
GL_COLOR_ATTACHMENT2,
|
||||
GL_COLOR_ATTACHMENT3,
|
||||
GL_COLOR_ATTACHMENT4,
|
||||
GL_COLOR_ATTACHMENT5,
|
||||
GL_COLOR_ATTACHMENT6,
|
||||
GL_COLOR_ATTACHMENT7,
|
||||
GL_COLOR_ATTACHMENT8,
|
||||
GL_COLOR_ATTACHMENT9,
|
||||
GL_COLOR_ATTACHMENT10,
|
||||
GL_COLOR_ATTACHMENT11,
|
||||
GL_COLOR_ATTACHMENT12,
|
||||
GL_COLOR_ATTACHMENT13,
|
||||
GL_COLOR_ATTACHMENT14,
|
||||
GL_COLOR_ATTACHMENT15 };
|
||||
|
||||
int unit = 0;
|
||||
for (auto& b : framebuffer.getRenderBuffers()) {
|
||||
auto surface = b._texture;
|
||||
if (surface) {
|
||||
auto gltexture = GLBackend::syncGPUObject(*surface);
|
||||
if (gltexture) {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0);
|
||||
}
|
||||
colorBuffers[nbColorBuffers] = colorAttachments[unit];
|
||||
nbColorBuffers++;
|
||||
unit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (framebuffer.hasDepthStencil()) {
|
||||
auto surface = framebuffer.getDepthStencilBuffer();
|
||||
if (surface) {
|
||||
auto gltexture = GLBackend::syncGPUObject(*surface);
|
||||
if (gltexture) {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, gltexture->_texture, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Last but not least, define where we draw
|
||||
if (nbColorBuffers > 0) {
|
||||
glDrawBuffers(nbColorBuffers, colorBuffers);
|
||||
} else {
|
||||
glDrawBuffer( GL_NONE );
|
||||
}
|
||||
|
||||
// Now check for completness
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
bool result = false;
|
||||
switch (status) {
|
||||
case GL_FRAMEBUFFER_COMPLETE :
|
||||
// Success !
|
||||
result = true;
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT :
|
||||
qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT.";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT :
|
||||
qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT.";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER :
|
||||
qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER.";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER :
|
||||
qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER.";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED :
|
||||
qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED.";
|
||||
break;
|
||||
}
|
||||
if (!result && fbo) {
|
||||
glDeleteFramebuffers( 1, &fbo );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// All is green, assign the gpuobject to the Framebuffer
|
||||
object = new GLFramebuffer();
|
||||
object->_fbo = fbo;
|
||||
Backend::setGPUObject(framebuffer, object);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLuint GLBackend::getFramebufferID(const FramebufferPointer& framebuffer) {
|
||||
if (!framebuffer) {
|
||||
return 0;
|
||||
}
|
||||
GLFramebuffer* object = GLBackend::syncGPUObject(*framebuffer);
|
||||
if (object) {
|
||||
return object->_fbo;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) {
|
||||
auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
|
||||
|
||||
if (_output._framebuffer != framebuffer) {
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getFramebufferID(framebuffer));
|
||||
_output._framebuffer = framebuffer;
|
||||
}
|
||||
}
|
||||
|
|
@ -237,26 +237,26 @@ void GLBackend::resetPipelineState(State::Signature nextSignature) {
|
|||
}
|
||||
}
|
||||
|
||||
State::ComparisonFunction comparisonFuncFromGL(GLenum func) {
|
||||
ComparisonFunction comparisonFuncFromGL(GLenum func) {
|
||||
if (func == GL_NEVER) {
|
||||
return State::NEVER;
|
||||
return NEVER;
|
||||
} else if (func == GL_LESS) {
|
||||
return State::LESS;
|
||||
return LESS;
|
||||
} else if (func == GL_EQUAL) {
|
||||
return State::EQUAL;
|
||||
return EQUAL;
|
||||
} else if (func == GL_LEQUAL) {
|
||||
return State::LESS_EQUAL;
|
||||
return LESS_EQUAL;
|
||||
} else if (func == GL_GREATER) {
|
||||
return State::GREATER;
|
||||
return GREATER;
|
||||
} else if (func == GL_NOTEQUAL) {
|
||||
return State::NOT_EQUAL;
|
||||
return NOT_EQUAL;
|
||||
} else if (func == GL_GEQUAL) {
|
||||
return State::GREATER_EQUAL;
|
||||
return GREATER_EQUAL;
|
||||
} else if (func == GL_ALWAYS) {
|
||||
return State::ALWAYS;
|
||||
return ALWAYS;
|
||||
}
|
||||
|
||||
return State::ALWAYS;
|
||||
return ALWAYS;
|
||||
}
|
||||
|
||||
State::StencilOp stencilOpFromGL(GLenum stencilOp) {
|
||||
|
|
|
@ -16,7 +16,8 @@ GLBackend::GLTexture::GLTexture() :
|
|||
_storageStamp(0),
|
||||
_contentStamp(0),
|
||||
_texture(0),
|
||||
_size(0)
|
||||
_size(0),
|
||||
_target(GL_TEXTURE_2D)
|
||||
{}
|
||||
|
||||
GLBackend::GLTexture::~GLTexture() {
|
||||
|
@ -144,7 +145,38 @@ public:
|
|||
texel.internalFormat = GL_RED;
|
||||
break;
|
||||
case gpu::DEPTH:
|
||||
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
case gpu::INT32:
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||
break;
|
||||
}
|
||||
case gpu::NFLOAT:
|
||||
case gpu::FLOAT: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32F;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT16:
|
||||
case gpu::INT16:
|
||||
case gpu::NUINT16:
|
||||
case gpu::NINT16:
|
||||
case gpu::HALF:
|
||||
case gpu::NHALF: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT16;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT8:
|
||||
case gpu::INT8:
|
||||
case gpu::NUINT8:
|
||||
case gpu::NINT8: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT24;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
|
@ -254,66 +286,77 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
|||
// GO through the process of allocating the correct storage and/or update the content
|
||||
switch (texture.getType()) {
|
||||
case Texture::TEX_2D: {
|
||||
if (needUpdate) {
|
||||
if (texture.isStoredMipAvailable(0)) {
|
||||
GLint boundTex = -1;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
|
||||
|
||||
Texture::PixelsPointer mip = texture.accessStoredMip(0);
|
||||
const GLvoid* bytes = mip->_sysmem.read<Resource::Byte>();
|
||||
Element srcFormat = mip->_format;
|
||||
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, object->_texture);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
||||
texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0,
|
||||
texelFormat.format, texelFormat.type, bytes);
|
||||
|
||||
if (texture.isAutogenerateMips()) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
|
||||
// At this point the mip piels have been loaded, we can notify
|
||||
texture.notifyGPULoaded(0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, boundTex);
|
||||
object->_contentStamp = texture.getDataStamp();
|
||||
}
|
||||
} else {
|
||||
const GLvoid* bytes = 0;
|
||||
Element srcFormat = texture.getTexelFormat();
|
||||
if (texture.isStoredMipAvailable(0)) {
|
||||
Texture::PixelsPointer mip = texture.accessStoredMip(0);
|
||||
|
||||
bytes = mip->_sysmem.read<Resource::Byte>();
|
||||
srcFormat = mip->_format;
|
||||
|
||||
object->_contentStamp = texture.getDataStamp();
|
||||
}
|
||||
|
||||
if (texture.getNumSlices() == 1) {
|
||||
GLint boundTex = -1;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
|
||||
glBindTexture(GL_TEXTURE_2D, object->_texture);
|
||||
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0,
|
||||
texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0,
|
||||
texelFormat.format, texelFormat.type, bytes);
|
||||
if (needUpdate) {
|
||||
if (texture.isStoredMipAvailable(0)) {
|
||||
Texture::PixelsPointer mip = texture.accessStoredMip(0);
|
||||
const GLvoid* bytes = mip->_sysmem.read<Resource::Byte>();
|
||||
Element srcFormat = mip->_format;
|
||||
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
|
||||
|
||||
if (bytes && texture.isAutogenerateMips()) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, object->_texture);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
||||
texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0,
|
||||
texelFormat.format, texelFormat.type, bytes);
|
||||
|
||||
if (texture.isAutogenerateMips()) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
|
||||
object->_target = GL_TEXTURE_2D;
|
||||
|
||||
syncSampler(texture.getSampler(), texture.getType(), object);
|
||||
|
||||
|
||||
// At this point the mip piels have been loaded, we can notify
|
||||
texture.notifyGPULoaded(0);
|
||||
|
||||
object->_contentStamp = texture.getDataStamp();
|
||||
}
|
||||
} else {
|
||||
const GLvoid* bytes = 0;
|
||||
Element srcFormat = texture.getTexelFormat();
|
||||
if (texture.isStoredMipAvailable(0)) {
|
||||
Texture::PixelsPointer mip = texture.accessStoredMip(0);
|
||||
|
||||
bytes = mip->_sysmem.read<Resource::Byte>();
|
||||
srcFormat = mip->_format;
|
||||
|
||||
object->_contentStamp = texture.getDataStamp();
|
||||
}
|
||||
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0,
|
||||
texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0,
|
||||
texelFormat.format, texelFormat.type, bytes);
|
||||
|
||||
if (bytes && texture.isAutogenerateMips()) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
object->_target = GL_TEXTURE_2D;
|
||||
|
||||
syncSampler(texture.getSampler(), texture.getType(), object);
|
||||
|
||||
// At this point the mip piels have been loaded, we can notify
|
||||
texture.notifyGPULoaded(0);
|
||||
|
||||
object->_storageStamp = texture.getStamp();
|
||||
object->_size = texture.getSize();
|
||||
}
|
||||
|
||||
// At this point the mip piels have been loaded, we can notify
|
||||
texture.notifyGPULoaded(0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, boundTex);
|
||||
object->_storageStamp = texture.getStamp();
|
||||
object->_size = texture.getSize();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -339,3 +382,70 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture) {
|
|||
}
|
||||
}
|
||||
|
||||
void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTexture* object) {
|
||||
if (!object) return;
|
||||
if (!object->_texture) return;
|
||||
|
||||
class GLFilterMode {
|
||||
public:
|
||||
GLint minFilter;
|
||||
GLint magFilter;
|
||||
};
|
||||
static const GLFilterMode filterModes[] = {
|
||||
{GL_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_POINT,
|
||||
{GL_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR,
|
||||
{GL_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT,
|
||||
{GL_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR,
|
||||
|
||||
{GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT,
|
||||
{GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT,
|
||||
{GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_MAG_POINT_MIP_LINEAR,
|
||||
{GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
|
||||
{GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_POINT_MAG_MIP_LINEAR,
|
||||
{GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_MIP_POINT,
|
||||
{GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
|
||||
{GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR_MIP_POINT,
|
||||
{GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_MIP_LINEAR,
|
||||
{GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} //FILTER_ANISOTROPIC,
|
||||
};
|
||||
|
||||
auto fm = filterModes[sampler.getFilter()];
|
||||
glTexParameteri(object->_target, GL_TEXTURE_MIN_FILTER, fm.minFilter);
|
||||
glTexParameteri(object->_target, GL_TEXTURE_MAG_FILTER, fm.magFilter);
|
||||
|
||||
static const GLenum comparisonFuncs[] = {
|
||||
GL_NEVER,
|
||||
GL_LESS,
|
||||
GL_EQUAL,
|
||||
GL_LEQUAL,
|
||||
GL_GREATER,
|
||||
GL_NOTEQUAL,
|
||||
GL_GEQUAL,
|
||||
GL_ALWAYS };
|
||||
|
||||
if (sampler.doComparison()) {
|
||||
glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
||||
glTexParameteri(object->_target, GL_TEXTURE_COMPARE_FUNC, comparisonFuncs[sampler.getComparisonFunction()]);
|
||||
} else {
|
||||
glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
}
|
||||
|
||||
static const GLenum wrapModes[] = {
|
||||
GL_REPEAT, // WRAP_REPEAT,
|
||||
GL_MIRRORED_REPEAT, // WRAP_MIRROR,
|
||||
GL_CLAMP_TO_EDGE, // WRAP_CLAMP,
|
||||
GL_CLAMP_TO_BORDER, // WRAP_BORDER,
|
||||
GL_MIRROR_CLAMP_TO_EDGE_EXT }; // WRAP_MIRROR_ONCE,
|
||||
|
||||
glTexParameteri(object->_target, GL_TEXTURE_WRAP_S, wrapModes[sampler.getWrapModeU()]);
|
||||
glTexParameteri(object->_target, GL_TEXTURE_WRAP_T, wrapModes[sampler.getWrapModeV()]);
|
||||
glTexParameteri(object->_target, GL_TEXTURE_WRAP_R, wrapModes[sampler.getWrapModeW()]);
|
||||
|
||||
glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*) &sampler.getBorderColor());
|
||||
glTexParameteri(object->_target, GL_TEXTURE_BASE_LEVEL, sampler.getMipOffset());
|
||||
glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float) sampler.getMinMip());
|
||||
glTexParameterf(object->_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
|
||||
glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
using namespace gpu;
|
||||
|
||||
const Element Element::COLOR_RGBA_32 = Element(VEC4, UINT8, RGBA);
|
||||
|
||||
Resource::Size Resource::Sysmem::allocateMemory(Byte** dataAllocated, Size size) {
|
||||
if ( !dataAllocated ) {
|
||||
qWarning() << "Buffer::Sysmem::allocateMemory() : Must have a valid dataAllocated pointer.";
|
||||
|
|
|
@ -42,19 +42,8 @@ public:
|
|||
virtual ~State();
|
||||
|
||||
const Stamp getStamp() const { return _stamp; }
|
||||
|
||||
enum ComparisonFunction {
|
||||
NEVER = 0,
|
||||
LESS,
|
||||
EQUAL,
|
||||
LESS_EQUAL,
|
||||
GREATER,
|
||||
NOT_EQUAL,
|
||||
GREATER_EQUAL,
|
||||
ALWAYS,
|
||||
|
||||
NUM_COMPARISON_FUNCS,
|
||||
};
|
||||
|
||||
typedef ::gpu::ComparisonFunction ComparisonFunction;
|
||||
|
||||
enum FillMode {
|
||||
FILL_POINT = 0,
|
||||
|
@ -415,5 +404,4 @@ typedef std::vector< StatePointer > States;
|
|||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -93,23 +93,23 @@ bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size s
|
|||
return allocated == size;
|
||||
}
|
||||
|
||||
Texture* Texture::create1D(const Element& texelFormat, uint16 width) {
|
||||
return create(TEX_1D, texelFormat, width, 1, 1, 1, 1);
|
||||
Texture* Texture::create1D(const Element& texelFormat, uint16 width, const Sampler& sampler) {
|
||||
return create(TEX_1D, texelFormat, width, 1, 1, 1, 1, sampler);
|
||||
}
|
||||
|
||||
Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height) {
|
||||
return create(TEX_2D, texelFormat, width, height, 1, 1, 1);
|
||||
Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) {
|
||||
return create(TEX_2D, texelFormat, width, height, 1, 1, 1, sampler);
|
||||
}
|
||||
|
||||
Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth) {
|
||||
return create(TEX_3D, texelFormat, width, height, depth, 1, 1);
|
||||
Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler) {
|
||||
return create(TEX_3D, texelFormat, width, height, depth, 1, 1, sampler);
|
||||
}
|
||||
|
||||
Texture* Texture::createCube(const Element& texelFormat, uint16 width) {
|
||||
return create(TEX_CUBE, texelFormat, width, width, 1, 1, 1);
|
||||
Texture* Texture::createCube(const Element& texelFormat, uint16 width, const Sampler& sampler) {
|
||||
return create(TEX_CUBE, texelFormat, width, width, 1, 1, 1, sampler);
|
||||
}
|
||||
|
||||
Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices)
|
||||
Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler)
|
||||
{
|
||||
Texture* tex = new Texture();
|
||||
tex->_storage.reset(new Storage());
|
||||
|
@ -118,6 +118,8 @@ Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, ui
|
|||
tex->_maxMip = 0;
|
||||
tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices);
|
||||
|
||||
tex->_sampler = sampler;
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
|
@ -346,3 +348,8 @@ uint16 Texture::evalNumSamplesUsed(uint16 numSamplesTried) {
|
|||
|
||||
return sample;
|
||||
}
|
||||
|
||||
void Texture::setSampler(const Sampler& sampler) {
|
||||
_sampler = sampler;
|
||||
_samplerStamp++;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,85 @@
|
|||
|
||||
namespace gpu {
|
||||
|
||||
class Sampler {
|
||||
public:
|
||||
|
||||
enum Filter {
|
||||
FILTER_MIN_MAG_POINT, // top mip only
|
||||
FILTER_MIN_POINT_MAG_LINEAR, // top mip only
|
||||
FILTER_MIN_LINEAR_MAG_POINT, // top mip only
|
||||
FILTER_MIN_MAG_LINEAR, // top mip only
|
||||
|
||||
FILTER_MIN_MAG_MIP_POINT,
|
||||
FILTER_MIN_MAG_POINT_MIP_LINEAR,
|
||||
FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
|
||||
FILTER_MIN_POINT_MAG_MIP_LINEAR,
|
||||
FILTER_MIN_LINEAR_MAG_MIP_POINT,
|
||||
FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
|
||||
FILTER_MIN_MAG_LINEAR_MIP_POINT,
|
||||
FILTER_MIN_MAG_MIP_LINEAR,
|
||||
FILTER_ANISOTROPIC,
|
||||
|
||||
NUM_FILTERS,
|
||||
};
|
||||
|
||||
enum WrapMode {
|
||||
WRAP_REPEAT = 0,
|
||||
WRAP_MIRROR,
|
||||
WRAP_CLAMP,
|
||||
WRAP_BORDER,
|
||||
WRAP_MIRROR_ONCE,
|
||||
|
||||
NUM_WRAP_MODES
|
||||
};
|
||||
|
||||
static const uint8 MAX_MIP_LEVEL = 0xFF;
|
||||
|
||||
class Desc {
|
||||
public:
|
||||
glm::vec4 _borderColor{ 1.0f };
|
||||
uint32 _maxAnisotropy = 16;
|
||||
|
||||
uint8 _wrapModeU = WRAP_REPEAT;
|
||||
uint8 _wrapModeV = WRAP_REPEAT;
|
||||
uint8 _wrapModeW = WRAP_REPEAT;
|
||||
|
||||
uint8 _filter = FILTER_MIN_MAG_POINT;
|
||||
uint8 _comparisonFunc = ALWAYS;
|
||||
|
||||
uint8 _mipOffset = 0;
|
||||
uint8 _minMip = 0;
|
||||
uint8 _maxMip = MAX_MIP_LEVEL;
|
||||
|
||||
Desc() {}
|
||||
Desc(const Filter filter) : _filter(filter) {}
|
||||
};
|
||||
|
||||
Sampler() {}
|
||||
Sampler(const Filter filter) : _desc(filter) {}
|
||||
Sampler(const Desc& desc) : _desc(desc) {}
|
||||
~Sampler() {}
|
||||
|
||||
const glm::vec4& getBorderColor() const { return _desc._borderColor; }
|
||||
|
||||
uint32 getMaxAnisotropy() const { return _desc._maxAnisotropy; }
|
||||
|
||||
WrapMode getWrapModeU() const { return WrapMode(_desc._wrapModeU); }
|
||||
WrapMode getWrapModeV() const { return WrapMode(_desc._wrapModeV); }
|
||||
WrapMode getWrapModeW() const { return WrapMode(_desc._wrapModeW); }
|
||||
|
||||
Filter getFilter() const { return Filter(_desc._filter); }
|
||||
ComparisonFunction getComparisonFunction() const { return ComparisonFunction(_desc._comparisonFunc); }
|
||||
bool doComparison() const { return getComparisonFunction() != ALWAYS; }
|
||||
|
||||
uint8 getMipOffset() const { return _desc._mipOffset; }
|
||||
uint8 getMinMip() const { return _desc._minMip; }
|
||||
uint8 getMaxMip() const { return _desc._maxMip; }
|
||||
|
||||
protected:
|
||||
Desc _desc;
|
||||
};
|
||||
|
||||
class Texture : public Resource {
|
||||
public:
|
||||
|
||||
|
@ -61,10 +140,10 @@ public:
|
|||
TEX_CUBE,
|
||||
};
|
||||
|
||||
static Texture* create1D(const Element& texelFormat, uint16 width);
|
||||
static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height);
|
||||
static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth);
|
||||
static Texture* createCube(const Element& texelFormat, uint16 width);
|
||||
static Texture* create1D(const Element& texelFormat, uint16 width, const Sampler& sampler = Sampler());
|
||||
static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler = Sampler());
|
||||
static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler = Sampler());
|
||||
static Texture* createCube(const Element& texelFormat, uint16 width, const Sampler& sampler = Sampler());
|
||||
|
||||
static Texture* createFromStorage(Storage* storage);
|
||||
|
||||
|
@ -181,11 +260,21 @@ public:
|
|||
|
||||
bool isDefined() const { return _defined; }
|
||||
|
||||
|
||||
// Own sampler
|
||||
void setSampler(const Sampler& sampler);
|
||||
const Sampler& getSampler() const { return _sampler; }
|
||||
const Stamp getSamplerStamp() const { return _samplerStamp; }
|
||||
|
||||
protected:
|
||||
std::unique_ptr< Storage > _storage;
|
||||
|
||||
Stamp _stamp;
|
||||
|
||||
Sampler _sampler;
|
||||
Stamp _samplerStamp;
|
||||
|
||||
|
||||
uint32 _size;
|
||||
Element _texelFormat;
|
||||
|
||||
|
@ -202,7 +291,7 @@ protected:
|
|||
bool _autoGenerateMips;
|
||||
bool _defined;
|
||||
|
||||
static Texture* create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
|
||||
static Texture* create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler);
|
||||
Texture();
|
||||
|
||||
Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
|
||||
|
@ -240,15 +329,25 @@ public:
|
|||
_subresource(0),
|
||||
_element(element)
|
||||
{};
|
||||
TextureView(const TexturePointer& texture, const Element& element) :
|
||||
TextureView(const TexturePointer& texture, uint16 subresource, const Element& element) :
|
||||
_texture(texture),
|
||||
_subresource(0),
|
||||
_subresource(subresource),
|
||||
_element(element)
|
||||
{};
|
||||
|
||||
TextureView(const TexturePointer& texture, uint16 subresource) :
|
||||
_texture(texture),
|
||||
_subresource(subresource)
|
||||
{};
|
||||
|
||||
~TextureView() {}
|
||||
TextureView(const TextureView& view) = default;
|
||||
TextureView& operator=(const TextureView& view) = default;
|
||||
|
||||
explicit operator bool() const { return (_texture); }
|
||||
bool operator !() const { return (!_texture); }
|
||||
};
|
||||
typedef std::vector<TextureView> TextureViews;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -245,7 +245,6 @@ void DynamicCharacterController::setEnabled(bool enabled) {
|
|||
// Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit.
|
||||
// Setting the ADD bit here works for all cases so we don't even bother checking other bits.
|
||||
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
|
||||
setHovering(true);
|
||||
} else {
|
||||
if (_dynamicsWorld) {
|
||||
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||
|
@ -253,6 +252,7 @@ void DynamicCharacterController::setEnabled(bool enabled) {
|
|||
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
|
||||
_isOnGround = false;
|
||||
}
|
||||
setHovering(true);
|
||||
_enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) {
|
|||
setHovering(true);
|
||||
}
|
||||
|
||||
_walkVelocity = glmToBullet(_avatarData->getVelocity());
|
||||
_walkVelocity = glmToBullet(_avatarData->getTargetVelocity());
|
||||
|
||||
if (_pendingFlags & PENDING_FLAG_JUMP) {
|
||||
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
||||
|
@ -408,6 +408,7 @@ void DynamicCharacterController::postSimulation() {
|
|||
|
||||
_avatarData->setOrientation(rotation);
|
||||
_avatarData->setPosition(position - rotation * _shapeLocalOffset);
|
||||
_avatarData->setVelocity(bulletToGLM(_rigidBody->getLinearVelocity()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,107 +14,6 @@
|
|||
#include "ShapeInfoUtil.h"
|
||||
#include "BulletUtil.h"
|
||||
|
||||
int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) {
|
||||
int bulletShapeType = INVALID_SHAPE_PROXYTYPE;
|
||||
switch(shapeInfoType) {
|
||||
case SHAPE_TYPE_BOX:
|
||||
bulletShapeType = BOX_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
bulletShapeType = SPHERE_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
case SHAPE_TYPE_CAPSULE_Y:
|
||||
bulletShapeType = CAPSULE_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
case SHAPE_TYPE_CONVEX_HULL:
|
||||
bulletShapeType = CONVEX_HULL_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND:
|
||||
bulletShapeType = COMPOUND_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
}
|
||||
return bulletShapeType;
|
||||
}
|
||||
|
||||
int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) {
|
||||
int shapeInfoType = SHAPE_TYPE_NONE;
|
||||
switch(bulletShapeType) {
|
||||
case BOX_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = SHAPE_TYPE_BOX;
|
||||
break;
|
||||
case SPHERE_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = SHAPE_TYPE_SPHERE;
|
||||
break;
|
||||
case CAPSULE_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = SHAPE_TYPE_CAPSULE_Y;
|
||||
break;
|
||||
case CONVEX_HULL_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = SHAPE_TYPE_CONVEX_HULL;
|
||||
break;
|
||||
case COMPOUND_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = SHAPE_TYPE_COMPOUND;
|
||||
break;
|
||||
}
|
||||
return shapeInfoType;
|
||||
}
|
||||
|
||||
void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info) {
|
||||
if (shape) {
|
||||
int type = ShapeInfoUtil::fromBulletShapeType(shape->getShapeType());
|
||||
switch(type) {
|
||||
case SHAPE_TYPE_BOX: {
|
||||
const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape);
|
||||
info.setBox(bulletToGLM(boxShape->getHalfExtentsWithMargin()));
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_SPHERE: {
|
||||
const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape);
|
||||
info.setSphere(sphereShape->getRadius());
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CONVEX_HULL: {
|
||||
const btConvexHullShape* convexHullShape = static_cast<const btConvexHullShape*>(shape);
|
||||
const int numPoints = convexHullShape->getNumPoints();
|
||||
const btVector3* btPoints = convexHullShape->getUnscaledPoints();
|
||||
QVector<QVector<glm::vec3>> points;
|
||||
QVector<glm::vec3> childPoints;
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ());
|
||||
childPoints << point;
|
||||
}
|
||||
points << childPoints;
|
||||
info.setConvexHulls(points);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND: {
|
||||
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shape);
|
||||
const int numChildShapes = compoundShape->getNumChildShapes();
|
||||
QVector<QVector<glm::vec3>> points;
|
||||
for (int i = 0; i < numChildShapes; i ++) {
|
||||
const btCollisionShape* childShape = compoundShape->getChildShape(i);
|
||||
const btConvexHullShape* convexHullShape = static_cast<const btConvexHullShape*>(childShape);
|
||||
const int numPoints = convexHullShape->getNumPoints();
|
||||
const btVector3* btPoints = convexHullShape->getUnscaledPoints();
|
||||
|
||||
QVector<glm::vec3> childPoints;
|
||||
for (int j = 0; j < numPoints; j++) {
|
||||
glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ());
|
||||
childPoints << point;
|
||||
}
|
||||
points << childPoints;
|
||||
}
|
||||
info.setConvexHulls(points);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
info.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
info.clear();
|
||||
}
|
||||
}
|
||||
|
||||
btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
|
||||
btCollisionShape* shape = NULL;
|
||||
|
@ -135,33 +34,34 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
|
|||
shape = new btCapsuleShape(radius, height);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CONVEX_HULL: {
|
||||
auto hull = new btConvexHullShape();
|
||||
const QVector<QVector<glm::vec3>>& points = info.getPoints();
|
||||
foreach (glm::vec3 point, points[0]) {
|
||||
btVector3 btPoint(point[0], point[1], point[2]);
|
||||
hull->addPoint(btPoint, false);
|
||||
}
|
||||
hull->recalcLocalAabb();
|
||||
shape = hull;
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND: {
|
||||
auto compound = new btCompoundShape();
|
||||
const QVector<QVector<glm::vec3>>& points = info.getPoints();
|
||||
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
foreach (QVector<glm::vec3> hullPoints, points) {
|
||||
uint32_t numSubShapes = info.getNumSubShapes();
|
||||
if (numSubShapes == 1) {
|
||||
auto hull = new btConvexHullShape();
|
||||
foreach (glm::vec3 point, hullPoints) {
|
||||
const QVector<QVector<glm::vec3>>& points = info.getPoints();
|
||||
foreach (glm::vec3 point, points[0]) {
|
||||
btVector3 btPoint(point[0], point[1], point[2]);
|
||||
hull->addPoint(btPoint, false);
|
||||
}
|
||||
hull->recalcLocalAabb();
|
||||
compound->addChildShape (trans, hull);
|
||||
shape = hull;
|
||||
} else {
|
||||
assert(numSubShapes > 1);
|
||||
auto compound = new btCompoundShape();
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
foreach (QVector<glm::vec3> hullPoints, points) {
|
||||
auto hull = new btConvexHullShape();
|
||||
foreach (glm::vec3 point, hullPoints) {
|
||||
btVector3 btPoint(point[0], point[1], point[2]);
|
||||
hull->addPoint(btPoint, false);
|
||||
}
|
||||
hull->recalcLocalAabb();
|
||||
compound->addChildShape (trans, hull);
|
||||
}
|
||||
shape = compound;
|
||||
}
|
||||
shape = compound;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -19,16 +19,10 @@
|
|||
|
||||
// translates between ShapeInfo and btShape
|
||||
|
||||
// TODO: rename this to ShapeFactory
|
||||
namespace ShapeInfoUtil {
|
||||
|
||||
// XXX is collectInfoFromShape no longer strictly needed?
|
||||
void collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info);
|
||||
|
||||
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
|
||||
|
||||
// TODO? just use bullet shape types everywhere?
|
||||
int toBulletShapeType(int shapeInfoType);
|
||||
int fromBulletShapeType(int bulletShapeType);
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeInfoUtil_h
|
||||
|
|
|
@ -35,7 +35,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
|||
// Very small or large objects are not supported.
|
||||
float diagonal = 4.0f * glm::length2(info.getHalfExtents());
|
||||
const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube
|
||||
const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e6f; // 1000 m cube
|
||||
//const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e6f; // 1000 m cube
|
||||
if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED /* || diagonal > MAX_SHAPE_DIAGONAL_SQUARED*/ ) {
|
||||
// qCDebug(physics) << "ShapeManager::getShape -- not making shape due to size" << diagonal;
|
||||
return NULL;
|
||||
|
@ -104,11 +104,9 @@ void ShapeManager::collectGarbage() {
|
|||
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
if (shapeRef && shapeRef->refCount == 0) {
|
||||
// if the shape we're about to delete is compound, delete the children first.
|
||||
auto shapeType = ShapeInfoUtil::fromBulletShapeType(shapeRef->shape->getShapeType());
|
||||
if (shapeType == SHAPE_TYPE_COMPOUND) {
|
||||
if (shapeRef->shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
|
||||
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shapeRef->shape);
|
||||
const int numChildShapes = compoundShape->getNumChildShapes();
|
||||
QVector<QVector<glm::vec3>> points;
|
||||
for (int i = 0; i < numChildShapes; i ++) {
|
||||
const btCollisionShape* childShape = compoundShape->getChildShape(i);
|
||||
delete childShape;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
|
||||
#include <gpu/GPUConfig.h>
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <gpu/GLBackend.h>
|
||||
|
||||
#include <glm/gtc/random.hpp>
|
||||
|
||||
|
@ -107,8 +107,8 @@ void AmbientOcclusionEffect::render() {
|
|||
glBindTexture(GL_TEXTURE_2D, _rotationTextureID);
|
||||
|
||||
// render with the occlusion shader to the secondary/tertiary buffer
|
||||
QOpenGLFramebufferObject* freeFBO = DependencyManager::get<GlowEffect>()->getFreeFramebufferObject();
|
||||
freeFBO->bind();
|
||||
auto freeFramebuffer = DependencyManager::get<GlowEffect>()->getFreeFramebuffer();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(freeFramebuffer));
|
||||
|
||||
float left, right, bottom, top, nearVal, farVal;
|
||||
glm::vec4 nearClipPlane, farClipPlane;
|
||||
|
@ -118,9 +118,10 @@ void AmbientOcclusionEffect::render() {
|
|||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
const int VIEWPORT_X_INDEX = 0;
|
||||
const int VIEWPORT_WIDTH_INDEX = 2;
|
||||
QOpenGLFramebufferObject* primaryFBO = DependencyManager::get<TextureCache>()->getPrimaryFramebufferObject();
|
||||
float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width();
|
||||
float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width();
|
||||
|
||||
auto framebufferSize = DependencyManager::get<TextureCache>()->getFrameBufferSize();
|
||||
float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width();
|
||||
float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width();
|
||||
|
||||
_occlusionProgram->bind();
|
||||
_occlusionProgram->setUniformValue(_nearLocation, nearVal);
|
||||
|
@ -128,7 +129,7 @@ void AmbientOcclusionEffect::render() {
|
|||
_occlusionProgram->setUniformValue(_leftBottomLocation, left, bottom);
|
||||
_occlusionProgram->setUniformValue(_rightTopLocation, right, top);
|
||||
_occlusionProgram->setUniformValue(_noiseScaleLocation, viewport[VIEWPORT_WIDTH_INDEX] / (float)ROTATION_WIDTH,
|
||||
primaryFBO->height() / (float)ROTATION_HEIGHT);
|
||||
framebufferSize.height() / (float)ROTATION_HEIGHT);
|
||||
_occlusionProgram->setUniformValue(_texCoordOffsetLocation, sMin, 0.0f);
|
||||
_occlusionProgram->setUniformValue(_texCoordScaleLocation, sWidth, 1.0f);
|
||||
|
||||
|
@ -136,22 +137,24 @@ void AmbientOcclusionEffect::render() {
|
|||
|
||||
_occlusionProgram->release();
|
||||
|
||||
freeFBO->release();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
// now render secondary to primary with 4x4 blur
|
||||
DependencyManager::get<TextureCache>()->getPrimaryFramebufferObject()->bind();
|
||||
|
||||
auto primaryFramebuffer = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer));
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, freeFBO->texture());
|
||||
auto freeFramebufferTexture = freeFramebuffer->getRenderBuffer(0);
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(freeFramebufferTexture));
|
||||
|
||||
_blurProgram->bind();
|
||||
_blurProgram->setUniformValue(_blurScaleLocation, 1.0f / primaryFBO->width(), 1.0f / primaryFBO->height());
|
||||
_blurProgram->setUniformValue(_blurScaleLocation, 1.0f / framebufferSize.width(), 1.0f / framebufferSize.height());
|
||||
|
||||
renderFullscreenQuad(sMin, sMin + sWidth);
|
||||
|
||||
|
|
|
@ -47,10 +47,11 @@ void AnimationHandle::setPriority(float priority) {
|
|||
}
|
||||
|
||||
void AnimationHandle::setStartAutomatically(bool startAutomatically) {
|
||||
_animationLoop.setStartAutomatically(startAutomatically);
|
||||
if (getStartAutomatically() && !isRunning()) {
|
||||
if (startAutomatically && !isRunning()) {
|
||||
// Start before setting _animationLoop value so that code in setRunning() is executed
|
||||
start();
|
||||
}
|
||||
_animationLoop.setStartAutomatically(startAutomatically);
|
||||
}
|
||||
|
||||
void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) {
|
||||
|
@ -59,13 +60,10 @@ void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) {
|
|||
}
|
||||
|
||||
void AnimationHandle::setRunning(bool running) {
|
||||
if (isRunning() == running) {
|
||||
if (running && isRunning()) {
|
||||
// if we're already running, this is the same as a restart
|
||||
if (running) {
|
||||
// move back to the beginning
|
||||
setFrameIndex(getFirstFrame());
|
||||
return;
|
||||
}
|
||||
setFrameIndex(getFirstFrame());
|
||||
return;
|
||||
}
|
||||
_animationLoop.setRunning(running);
|
||||
if (isRunning()) {
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
|
||||
#include <gpu/GPUConfig.h>
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <PathUtils.h>
|
||||
|
@ -183,15 +182,18 @@ void DeferredLightingEffect::render() {
|
|||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
QOpenGLFramebufferObject* primaryFBO = textureCache->getPrimaryFramebufferObject();
|
||||
primaryFBO->release();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0 );
|
||||
|
||||
QSize framebufferSize = textureCache->getFrameBufferSize();
|
||||
|
||||
QOpenGLFramebufferObject* freeFBO = DependencyManager::get<GlowEffect>()->getFreeFramebufferObject();
|
||||
freeFBO->bind();
|
||||
auto freeFBO = DependencyManager::get<GlowEffect>()->getFreeFramebuffer();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(freeFBO));
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
// glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
|
||||
// glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
|
||||
glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryColorTextureID());
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryNormalTextureID());
|
||||
|
@ -209,11 +211,13 @@ void DeferredLightingEffect::render() {
|
|||
const int VIEWPORT_Y_INDEX = 1;
|
||||
const int VIEWPORT_WIDTH_INDEX = 2;
|
||||
const int VIEWPORT_HEIGHT_INDEX = 3;
|
||||
float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width();
|
||||
float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width();
|
||||
float tMin = viewport[VIEWPORT_Y_INDEX] / (float)primaryFBO->height();
|
||||
float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)primaryFBO->height();
|
||||
|
||||
|
||||
float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width();
|
||||
float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width();
|
||||
float tMin = viewport[VIEWPORT_Y_INDEX] / (float)framebufferSize.height();
|
||||
float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)framebufferSize.height();
|
||||
|
||||
|
||||
// Fetch the ViewMatrix;
|
||||
glm::mat4 invViewMat;
|
||||
_viewState->getViewTransform().getMatrix(invViewMat);
|
||||
|
@ -245,7 +249,7 @@ void DeferredLightingEffect::render() {
|
|||
program->bind();
|
||||
}
|
||||
program->setUniformValue(locations->shadowScale,
|
||||
1.0f / textureCache->getShadowFramebufferObject()->width());
|
||||
1.0f / textureCache->getShadowFramebuffer()->getWidth());
|
||||
|
||||
} else {
|
||||
if (_ambientLightMode > -1) {
|
||||
|
@ -428,7 +432,9 @@ void DeferredLightingEffect::render() {
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
freeFBO->release();
|
||||
//freeFBO->release();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
@ -437,9 +443,12 @@ void DeferredLightingEffect::render() {
|
|||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
glColorMask(true, true, true, false);
|
||||
|
||||
primaryFBO->bind();
|
||||
auto primaryFBO = gpu::GLBackend::getFramebufferID(textureCache->getPrimaryFramebuffer());
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, primaryFBO);
|
||||
|
||||
//primaryFBO->bind();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, freeFBO->texture());
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(freeFBO->getRenderBuffer(0)));
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glPushMatrix();
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "TextureCache.h"
|
||||
#include "RenderUtilsLogging.h"
|
||||
|
||||
#include "gpu/GLBackend.h"
|
||||
|
||||
GlowEffect::GlowEffect()
|
||||
: _initialized(false),
|
||||
|
@ -45,10 +46,10 @@ GlowEffect::~GlowEffect() {
|
|||
}
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* GlowEffect::getFreeFramebufferObject() const {
|
||||
gpu::FramebufferPointer GlowEffect::getFreeFramebuffer() const {
|
||||
return (_isOddFrame ?
|
||||
DependencyManager::get<TextureCache>()->getSecondaryFramebufferObject():
|
||||
DependencyManager::get<TextureCache>()->getTertiaryFramebufferObject());
|
||||
DependencyManager::get<TextureCache>()->getSecondaryFramebuffer():
|
||||
DependencyManager::get<TextureCache>()->getTertiaryFramebuffer());
|
||||
}
|
||||
|
||||
static ProgramObject* createProgram(const QString& name) {
|
||||
|
@ -105,7 +106,10 @@ int GlowEffect::getDeviceHeight() const {
|
|||
|
||||
|
||||
void GlowEffect::prepare() {
|
||||
DependencyManager::get<TextureCache>()->getPrimaryFramebufferObject()->bind();
|
||||
auto primaryFBO = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
|
||||
GLuint fbo = gpu::GLBackend::getFramebufferID(primaryFBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
_isEmpty = true;
|
||||
|
@ -124,25 +128,28 @@ void GlowEffect::end() {
|
|||
glBlendColor(0.0f, 0.0f, 0.0f, _intensity = _intensityStack.pop());
|
||||
}
|
||||
|
||||
static void maybeBind(QOpenGLFramebufferObject* fbo) {
|
||||
static void maybeBind(const gpu::FramebufferPointer& fbo) {
|
||||
if (fbo) {
|
||||
fbo->bind();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(fbo));
|
||||
}
|
||||
}
|
||||
|
||||
static void maybeRelease(QOpenGLFramebufferObject* fbo) {
|
||||
static void maybeRelease(const gpu::FramebufferPointer& fbo) {
|
||||
if (fbo) {
|
||||
fbo->release();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
|
||||
gpu::FramebufferPointer GlowEffect::render(bool toTexture) {
|
||||
PerformanceTimer perfTimer("glowEffect");
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
QOpenGLFramebufferObject* primaryFBO = textureCache->getPrimaryFramebufferObject();
|
||||
primaryFBO->release();
|
||||
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
|
||||
|
||||
auto primaryFBO = gpu::GLBackend::getFramebufferID(textureCache->getPrimaryFramebuffer());
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryColorTextureID());
|
||||
auto framebufferSize = textureCache->getFrameBufferSize();
|
||||
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
@ -155,12 +162,14 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
|
|||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
QOpenGLFramebufferObject* destFBO = toTexture ?
|
||||
textureCache->getSecondaryFramebufferObject() : NULL;
|
||||
gpu::FramebufferPointer destFBO = toTexture ?
|
||||
textureCache->getSecondaryFramebuffer() : nullptr;
|
||||
if (!_enabled || _isEmpty) {
|
||||
// copy the primary to the screen
|
||||
if (destFBO && QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
|
||||
QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO));
|
||||
glBlitFramebuffer(0, 0, framebufferSize.width(), framebufferSize.height(), 0, 0, framebufferSize.width(), framebufferSize.height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
} else {
|
||||
maybeBind(destFBO);
|
||||
if (!destFBO) {
|
||||
|
@ -175,35 +184,35 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
|
|||
}
|
||||
} else {
|
||||
// diffuse into the secondary/tertiary (alternating between frames)
|
||||
QOpenGLFramebufferObject* oldDiffusedFBO =
|
||||
textureCache->getSecondaryFramebufferObject();
|
||||
QOpenGLFramebufferObject* newDiffusedFBO =
|
||||
textureCache->getTertiaryFramebufferObject();
|
||||
auto oldDiffusedFBO =
|
||||
textureCache->getSecondaryFramebuffer();
|
||||
auto newDiffusedFBO =
|
||||
textureCache->getTertiaryFramebuffer();
|
||||
if (_isOddFrame) {
|
||||
qSwap(oldDiffusedFBO, newDiffusedFBO);
|
||||
}
|
||||
newDiffusedFBO->bind();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(newDiffusedFBO));
|
||||
|
||||
if (_isFirstFrame) {
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
} else {
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, oldDiffusedFBO->texture());
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(oldDiffusedFBO->getRenderBuffer(0)));
|
||||
|
||||
_diffuseProgram->bind();
|
||||
QSize size = primaryFBO->size();
|
||||
_diffuseProgram->setUniformValue(_diffusionScaleLocation, 1.0f / size.width(), 1.0f / size.height());
|
||||
|
||||
_diffuseProgram->setUniformValue(_diffusionScaleLocation, 1.0f / framebufferSize.width(), 1.0f / framebufferSize.height());
|
||||
|
||||
renderFullscreenQuad();
|
||||
|
||||
_diffuseProgram->release();
|
||||
}
|
||||
|
||||
newDiffusedFBO->release();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// add diffused texture to the primary
|
||||
glBindTexture(GL_TEXTURE_2D, newDiffusedFBO->texture());
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(newDiffusedFBO->getRenderBuffer(0)));
|
||||
|
||||
if (toTexture) {
|
||||
destFBO = oldDiffusedFBO;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_GlowEffect_h
|
||||
|
||||
#include <gpu/GPUConfig.h>
|
||||
#include <gpu/Framebuffer.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QGLWidget>
|
||||
|
@ -20,8 +21,6 @@
|
|||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
class QOpenGLFramebufferObject;
|
||||
|
||||
class ProgramObject;
|
||||
|
||||
/// A generic full screen glow effect.
|
||||
|
@ -33,7 +32,7 @@ public:
|
|||
|
||||
/// Returns a pointer to the framebuffer object that the glow effect is *not* using for persistent state
|
||||
/// (either the secondary or the tertiary).
|
||||
QOpenGLFramebufferObject* getFreeFramebufferObject() const;
|
||||
gpu::FramebufferPointer getFreeFramebuffer() const;
|
||||
|
||||
void init(QGLWidget* widget, bool enabled);
|
||||
|
||||
|
@ -53,7 +52,7 @@ public:
|
|||
/// Renders the glow effect. To be called after rendering the scene.
|
||||
/// \param toTexture whether to render to a texture, rather than to the frame buffer
|
||||
/// \return the framebuffer object to which we rendered, or NULL if to the frame buffer
|
||||
QOpenGLFramebufferObject* render(bool toTexture = false);
|
||||
gpu::FramebufferPointer render(bool toTexture = false);
|
||||
|
||||
public slots:
|
||||
void toggleGlowEffect(bool enabled);
|
||||
|
|
|
@ -130,7 +130,7 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key,
|
|||
}
|
||||
|
||||
// Z test depends if transparent or not
|
||||
state->setDepthTest(true, !key.isTranslucent(), gpu::State::LESS_EQUAL);
|
||||
state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL);
|
||||
|
||||
// Blend on transparent
|
||||
state->setBlendFunction(key.isTranslucent(),
|
||||
|
@ -151,7 +151,7 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key,
|
|||
|
||||
// create a new RenderPipeline with the same shader side and the mirrorState
|
||||
auto mirrorPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, mirrorState));
|
||||
auto it = insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations)));
|
||||
insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -673,8 +673,6 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// auto glowEffectIntensity = DependencyManager::get<GlowEffect>()->getIntensity();
|
||||
|
||||
// Let's introduce a gpu::Batch to capture all the calls to the graphics api
|
||||
_renderBatch.clear();
|
||||
gpu::Batch& batch = _renderBatch;
|
||||
|
@ -703,35 +701,12 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
|
|||
|
||||
batch.setViewTransform(_transforms[0]);
|
||||
|
||||
// GLBATCH(glDisable)(GL_COLOR_MATERIAL);
|
||||
|
||||
// taking care of by the state?
|
||||
/* if (mode == RenderArgs::DIFFUSE_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE) {
|
||||
GLBATCH(glDisable)(GL_CULL_FACE);
|
||||
} else {
|
||||
GLBATCH(glEnable)(GL_CULL_FACE);
|
||||
if (mode == RenderArgs::SHADOW_RENDER_MODE) {
|
||||
GLBATCH(glCullFace)(GL_FRONT);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// render opaque meshes with alpha testing
|
||||
|
||||
// GLBATCH(glDisable)(GL_BLEND);
|
||||
// GLBATCH(glEnable)(GL_ALPHA_TEST);
|
||||
|
||||
/* if (mode == RenderArgs::SHADOW_RENDER_MODE) {
|
||||
GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f);
|
||||
}
|
||||
*/
|
||||
|
||||
/*DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(
|
||||
mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE,
|
||||
mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE,
|
||||
mode == RenderArgs::DEFAULT_RENDER_MODE);
|
||||
*/
|
||||
{
|
||||
/*if (mode != RenderArgs::SHADOW_RENDER_MODE)*/ {
|
||||
GLenum buffers[3];
|
||||
int bufferCount = 0;
|
||||
|
||||
|
@ -748,6 +723,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
|
|||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
|
||||
}
|
||||
GLBATCH(glDrawBuffers)(bufferCount, buffers);
|
||||
// batch.setFramebuffer(DependencyManager::get<TextureCache>()->getPrimaryOpaqueFramebuffer());
|
||||
}
|
||||
|
||||
const float DEFAULT_ALPHA_THRESHOLD = 0.5f;
|
||||
|
@ -790,12 +766,6 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
|
|||
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args, true);
|
||||
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args, true);
|
||||
|
||||
// GLBATCH(glDisable)(GL_ALPHA_TEST);
|
||||
/* GLBATCH(glEnable)(GL_BLEND);
|
||||
GLBATCH(glDepthMask)(false);
|
||||
GLBATCH(glDepthFunc)(GL_LEQUAL);
|
||||
*/
|
||||
//DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(true);
|
||||
{
|
||||
GLenum buffers[1];
|
||||
int bufferCount = 0;
|
||||
|
@ -805,6 +775,8 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
|
|||
|
||||
// if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE) {
|
||||
if (mode != RenderArgs::SHADOW_RENDER_MODE) {
|
||||
// batch.setFramebuffer(DependencyManager::get<TextureCache>()->getPrimaryTransparentFramebuffer());
|
||||
|
||||
const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f;
|
||||
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args, true);
|
||||
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args, true);
|
||||
|
@ -814,6 +786,8 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
|
|||
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, args, true);
|
||||
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, args, true);
|
||||
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, args, true);
|
||||
|
||||
// batch.setFramebuffer(DependencyManager::get<TextureCache>()->getPrimaryOpaqueFramebuffer());
|
||||
}
|
||||
|
||||
GLBATCH(glDepthMask)(true);
|
||||
|
@ -1758,14 +1732,6 @@ void Model::setupBatchTransform(gpu::Batch& batch, RenderArgs* args) {
|
|||
void Model::endScene(RenderMode mode, RenderArgs* args) {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
|
||||
// auto glowEffectIntensity = DependencyManager::get<GlowEffect>()->getIntensity();
|
||||
|
||||
|
||||
#if defined(ANDROID)
|
||||
#else
|
||||
glPushMatrix();
|
||||
#endif
|
||||
|
||||
RenderArgs::RenderSide renderSide = RenderArgs::MONO;
|
||||
if (args) {
|
||||
renderSide = args->_renderSide;
|
||||
|
@ -1792,34 +1758,15 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
|
|||
_sceneRenderBatch.clear();
|
||||
gpu::Batch& batch = _sceneRenderBatch;
|
||||
|
||||
// GLBATCH(glDisable)(GL_COLOR_MATERIAL);
|
||||
|
||||
/* if (mode == RenderArgs::DIFFUSE_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE) {
|
||||
GLBATCH(glDisable)(GL_CULL_FACE);
|
||||
} else {
|
||||
GLBATCH(glEnable)(GL_CULL_FACE);
|
||||
if (mode == RenderArgs::SHADOW_RENDER_MODE) {
|
||||
GLBATCH(glCullFace)(GL_FRONT);
|
||||
}
|
||||
}*/
|
||||
|
||||
// render opaque meshes with alpha testing
|
||||
|
||||
// GLBATCH(glDisable)(GL_BLEND);
|
||||
// GLBATCH(glEnable)(GL_ALPHA_TEST);
|
||||
|
||||
/* if (mode == RenderArgs::SHADOW_RENDER_MODE) {
|
||||
GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f);
|
||||
}
|
||||
*/
|
||||
|
||||
/*DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(
|
||||
mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE,
|
||||
mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE,
|
||||
mode == RenderArgs::DEFAULT_RENDER_MODE);
|
||||
*/
|
||||
{
|
||||
|
||||
/* if (mode != RenderArgs::SHADOW_RENDER_MODE) */{
|
||||
GLenum buffers[3];
|
||||
|
||||
int bufferCount = 0;
|
||||
// if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE) {
|
||||
if (mode != RenderArgs::SHADOW_RENDER_MODE) {
|
||||
|
@ -1834,6 +1781,8 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
|
|||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
|
||||
}
|
||||
GLBATCH(glDrawBuffers)(bufferCount, buffers);
|
||||
|
||||
// batch.setFramebuffer(DependencyManager::get<TextureCache>()->getPrimaryOpaqueFramebuffer());
|
||||
}
|
||||
|
||||
const float DEFAULT_ALPHA_THRESHOLD = 0.5f;
|
||||
|
@ -1856,7 +1805,6 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
|
|||
opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, false, args);
|
||||
|
||||
// render translucent meshes afterwards
|
||||
//DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(false, true, true);
|
||||
{
|
||||
GLenum buffers[2];
|
||||
int bufferCount = 0;
|
||||
|
@ -1876,21 +1824,19 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
|
|||
translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args);
|
||||
translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args);
|
||||
|
||||
// GLBATCH(glDisable)(GL_ALPHA_TEST);
|
||||
/* GLBATCH(glEnable)(GL_BLEND);
|
||||
GLBATCH(glDepthMask)(false);
|
||||
GLBATCH(glDepthFunc)(GL_LEQUAL);
|
||||
*/
|
||||
//DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(true);
|
||||
|
||||
{
|
||||
GLenum buffers[1];
|
||||
int bufferCount = 0;
|
||||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
|
||||
GLBATCH(glDrawBuffers)(bufferCount, buffers);
|
||||
// batch.setFramebuffer(DependencyManager::get<TextureCache>()->getPrimaryTransparentFramebuffer());
|
||||
}
|
||||
|
||||
// if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE) {
|
||||
if (mode != RenderArgs::SHADOW_RENDER_MODE) {
|
||||
// batch.setFramebuffer(DependencyManager::get<TextureCache>()->getPrimaryTransparentFramebuffer());
|
||||
|
||||
const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f;
|
||||
translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args);
|
||||
translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args);
|
||||
|
@ -1900,6 +1846,8 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
|
|||
translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, args);
|
||||
translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, args);
|
||||
translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, args);
|
||||
|
||||
// batch.setFramebuffer(DependencyManager::get<TextureCache>()->getPrimaryOpaqueFramebuffer());
|
||||
}
|
||||
|
||||
GLBATCH(glDepthMask)(true);
|
||||
|
@ -1938,10 +1886,10 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
|
|||
// Back to no program
|
||||
GLBATCH(glUseProgram)(0);
|
||||
|
||||
if (args) {
|
||||
args->_translucentMeshPartsRendered = translucentParts;
|
||||
args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered;
|
||||
}
|
||||
if (args) {
|
||||
args->_translucentMeshPartsRendered = translucentParts;
|
||||
args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1951,12 +1899,6 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
|
|||
backend.render(_sceneRenderBatch);
|
||||
}
|
||||
|
||||
|
||||
#if defined(ANDROID)
|
||||
#else
|
||||
glPopMatrix();
|
||||
#endif
|
||||
|
||||
// restore all the default material settings
|
||||
_viewState->setupWorldLight();
|
||||
|
||||
|
@ -2334,17 +2276,15 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f
|
|||
RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned);
|
||||
auto pipeline = _renderPipelineLib.find(key.getRaw());
|
||||
if (pipeline == _renderPipelineLib.end()) {
|
||||
qDebug() << "No good, couldn;t find a pipeline from the key ?" << key.getRaw();
|
||||
qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw();
|
||||
return;
|
||||
}
|
||||
|
||||
gpu::ShaderPointer program = (*pipeline).second._pipeline->getProgram();
|
||||
locations = (*pipeline).second._locations.get();
|
||||
|
||||
//GLuint glprogram = gpu::GLBackend::getShaderID(program);
|
||||
//GLBATCH(glUseProgram)(glprogram);
|
||||
|
||||
// dare!
|
||||
// Setup the One pipeline
|
||||
batch.setPipeline((*pipeline).second._pipeline);
|
||||
|
||||
if ((locations->alphaThreshold > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) {
|
||||
|
@ -2354,9 +2294,6 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f
|
|||
if ((locations->glowIntensity > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) {
|
||||
GLBATCH(glUniform1f)(locations->glowIntensity, DependencyManager::get<GlowEffect>()->getIntensity());
|
||||
}
|
||||
// if (!(translucent && alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) {
|
||||
// GLBATCH(glAlphaFunc)(GL_EQUAL, DependencyManager::get<GlowEffect>()->getIntensity());
|
||||
// }
|
||||
}
|
||||
|
||||
int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold,
|
||||
|
@ -2383,10 +2320,7 @@ int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool
|
|||
}
|
||||
}
|
||||
}
|
||||
// if we selected a program, then unselect it
|
||||
if (!pickProgramsNeeded) {
|
||||
// GLBATCH(glUseProgram)(0);
|
||||
}
|
||||
|
||||
return meshPartsRendered;
|
||||
}
|
||||
|
||||
|
@ -2415,8 +2349,6 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl
|
|||
args, locations);
|
||||
meshPartsRendered = renderMeshesFromList(list, batch, mode, translucent, alphaThreshold,
|
||||
args, locations, forceRenderSomeMeshes);
|
||||
// GLBATCH(glUseProgram)(0);
|
||||
|
||||
|
||||
return meshPartsRendered;
|
||||
}
|
||||
|
@ -2427,7 +2359,7 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
|
|||
PROFILE_RANGE(__FUNCTION__);
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
// auto glowEffect = DependencyManager::get<GlowEffect>();
|
||||
|
||||
QString lastMaterialID;
|
||||
int meshPartsRendered = 0;
|
||||
updateVisibleJointStates();
|
||||
|
@ -2531,13 +2463,6 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
|
|||
qCDebug(renderutils) << "NEW part.materialID:" << part.materialID;
|
||||
}
|
||||
|
||||
/* if (locations->glowIntensity >= 0) {
|
||||
GLBATCH(glUniform1f)(locations->glowIntensity, glowEffect->getIntensity());
|
||||
}
|
||||
if (!(translucent && alphaThreshold == 0.0f)) {
|
||||
GLBATCH(glAlphaFunc)(GL_EQUAL, glowEffect->getIntensity());
|
||||
}
|
||||
*/
|
||||
if (locations->materialBufferUnit >= 0) {
|
||||
batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer());
|
||||
}
|
||||
|
|
|
@ -32,13 +32,6 @@ TextureCache::TextureCache() :
|
|||
_permutationNormalTexture(0),
|
||||
_whiteTexture(0),
|
||||
_blueTexture(0),
|
||||
_primaryDepthTextureID(0),
|
||||
_primaryNormalTextureID(0),
|
||||
_primarySpecularTextureID(0),
|
||||
_primaryFramebufferObject(NULL),
|
||||
_secondaryFramebufferObject(NULL),
|
||||
_tertiaryFramebufferObject(NULL),
|
||||
_shadowFramebufferObject(NULL),
|
||||
_frameBufferSize(100, 100),
|
||||
_associatedWidget(NULL)
|
||||
{
|
||||
|
@ -47,24 +40,6 @@ TextureCache::TextureCache() :
|
|||
}
|
||||
|
||||
TextureCache::~TextureCache() {
|
||||
|
||||
if (_primaryFramebufferObject) {
|
||||
glDeleteTextures(1, &_primaryDepthTextureID);
|
||||
glDeleteTextures(1, &_primaryNormalTextureID);
|
||||
glDeleteTextures(1, &_primarySpecularTextureID);
|
||||
}
|
||||
|
||||
if (_primaryFramebufferObject) {
|
||||
delete _primaryFramebufferObject;
|
||||
}
|
||||
|
||||
if (_secondaryFramebufferObject) {
|
||||
delete _secondaryFramebufferObject;
|
||||
}
|
||||
|
||||
if (_tertiaryFramebufferObject) {
|
||||
delete _tertiaryFramebufferObject;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::setFrameBufferSize(QSize frameBufferSize) {
|
||||
|
@ -72,26 +47,15 @@ void TextureCache::setFrameBufferSize(QSize frameBufferSize) {
|
|||
if (_frameBufferSize != frameBufferSize) {
|
||||
_frameBufferSize = frameBufferSize;
|
||||
|
||||
if (_primaryFramebufferObject) {
|
||||
delete _primaryFramebufferObject;
|
||||
_primaryFramebufferObject = NULL;
|
||||
glDeleteTextures(1, &_primaryDepthTextureID);
|
||||
_primaryDepthTextureID = 0;
|
||||
glDeleteTextures(1, &_primaryNormalTextureID);
|
||||
_primaryNormalTextureID = 0;
|
||||
glDeleteTextures(1, &_primarySpecularTextureID);
|
||||
_primarySpecularTextureID = 0;
|
||||
}
|
||||
_primaryFramebuffer.reset();
|
||||
_primaryDepthTexture.reset();
|
||||
_primaryColorTexture.reset();
|
||||
_primaryNormalTexture.reset();
|
||||
_primarySpecularTexture.reset();
|
||||
|
||||
if (_secondaryFramebufferObject) {
|
||||
delete _secondaryFramebufferObject;
|
||||
_secondaryFramebufferObject = NULL;
|
||||
}
|
||||
_secondaryFramebuffer.reset();
|
||||
|
||||
if (_tertiaryFramebufferObject) {
|
||||
delete _tertiaryFramebufferObject;
|
||||
_tertiaryFramebufferObject = NULL;
|
||||
}
|
||||
_tertiaryFramebuffer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,58 +170,78 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, TextureType type
|
|||
return texture;
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() {
|
||||
void TextureCache::createPrimaryFramebuffer() {
|
||||
_primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
|
||||
if (!_primaryFramebufferObject) {
|
||||
_primaryFramebufferObject = createFramebufferObject();
|
||||
auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
||||
auto width = _frameBufferSize.width();
|
||||
auto height = _frameBufferSize.height();
|
||||
|
||||
glGenTextures(1, &_primaryDepthTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, _primaryDepthTextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, _frameBufferSize.width(), _frameBufferSize.height(),
|
||||
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glGenTextures(1, &_primaryNormalTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, _primaryNormalTextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _frameBufferSize.width(), _frameBufferSize.height(),
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glGenTextures(1, &_primarySpecularTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, _primarySpecularTextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _frameBufferSize.width(), _frameBufferSize.height(),
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
_primaryFramebufferObject->bind();
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _primaryDepthTextureID, 0);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, _primaryNormalTextureID, 0);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, _primarySpecularTextureID, 0);
|
||||
_primaryFramebufferObject->release();
|
||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||
_primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||
_primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||
_primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||
|
||||
_primaryFramebuffer->setRenderBuffer(0, _primaryColorTexture);
|
||||
_primaryFramebuffer->setRenderBuffer(1, _primaryNormalTexture);
|
||||
_primaryFramebuffer->setRenderBuffer(2, _primarySpecularTexture);
|
||||
|
||||
|
||||
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
|
||||
_primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler));
|
||||
|
||||
_primaryFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer TextureCache::getPrimaryFramebuffer() {
|
||||
if (!_primaryFramebuffer) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primaryFramebufferObject;
|
||||
return _primaryFramebuffer;
|
||||
}
|
||||
|
||||
gpu::TexturePointer TextureCache::getPrimaryDepthTexture() {
|
||||
if (!_primaryDepthTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primaryDepthTexture;
|
||||
}
|
||||
|
||||
gpu::TexturePointer TextureCache::getPrimaryColorTexture() {
|
||||
if (!_primaryColorTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primaryColorTexture;
|
||||
}
|
||||
|
||||
gpu::TexturePointer TextureCache::getPrimaryNormalTexture() {
|
||||
if (!_primaryNormalTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primaryNormalTexture;
|
||||
}
|
||||
|
||||
gpu::TexturePointer TextureCache::getPrimarySpecularTexture() {
|
||||
if (!_primarySpecularTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primarySpecularTexture;
|
||||
}
|
||||
|
||||
GLuint TextureCache::getPrimaryDepthTextureID() {
|
||||
// ensure that the primary framebuffer object is initialized before returning the depth texture id
|
||||
getPrimaryFramebufferObject();
|
||||
return _primaryDepthTextureID;
|
||||
return gpu::GLBackend::getTextureID(getPrimaryDepthTexture());
|
||||
}
|
||||
|
||||
GLuint TextureCache::getPrimaryColorTextureID() {
|
||||
return gpu::GLBackend::getTextureID(getPrimaryColorTexture());
|
||||
}
|
||||
|
||||
GLuint TextureCache::getPrimaryNormalTextureID() {
|
||||
// ensure that the primary framebuffer object is initialized before returning the normal texture id
|
||||
getPrimaryFramebufferObject();
|
||||
return _primaryNormalTextureID;
|
||||
return gpu::GLBackend::getTextureID(getPrimaryNormalTexture());
|
||||
}
|
||||
|
||||
GLuint TextureCache::getPrimarySpecularTextureID() {
|
||||
getPrimaryFramebufferObject();
|
||||
return _primarySpecularTextureID;
|
||||
return gpu::GLBackend::getTextureID(getPrimarySpecularTexture());
|
||||
}
|
||||
|
||||
void TextureCache::setPrimaryDrawBuffers(bool color, bool normal, bool specular) {
|
||||
|
@ -275,70 +259,50 @@ void TextureCache::setPrimaryDrawBuffers(bool color, bool normal, bool specular)
|
|||
glDrawBuffers(bufferCount, buffers);
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() {
|
||||
if (!_secondaryFramebufferObject) {
|
||||
_secondaryFramebufferObject = createFramebufferObject();
|
||||
gpu::FramebufferPointer TextureCache::getSecondaryFramebuffer() {
|
||||
if (!_secondaryFramebuffer) {
|
||||
_secondaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, _frameBufferSize.width(), _frameBufferSize.height()));
|
||||
}
|
||||
return _secondaryFramebufferObject;
|
||||
return _secondaryFramebuffer;
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* TextureCache::getTertiaryFramebufferObject() {
|
||||
if (!_tertiaryFramebufferObject) {
|
||||
_tertiaryFramebufferObject = createFramebufferObject();
|
||||
gpu::FramebufferPointer TextureCache::getTertiaryFramebuffer() {
|
||||
if (!_tertiaryFramebuffer) {
|
||||
_tertiaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, _frameBufferSize.width(), _frameBufferSize.height()));
|
||||
}
|
||||
return _tertiaryFramebufferObject;
|
||||
return _tertiaryFramebuffer;
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* TextureCache::getShadowFramebufferObject() {
|
||||
if (!_shadowFramebufferObject) {
|
||||
|
||||
gpu::FramebufferPointer TextureCache::getShadowFramebuffer() {
|
||||
if (!_shadowFramebuffer) {
|
||||
const int SHADOW_MAP_SIZE = 2048;
|
||||
_shadowFramebufferObject = new QOpenGLFramebufferObject(SHADOW_MAP_SIZE, SHADOW_MAP_SIZE,
|
||||
QOpenGLFramebufferObject::NoAttachment, GL_TEXTURE_2D, GL_RGB);
|
||||
|
||||
glGenTextures(1, &_shadowDepthTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, _shadowDepthTextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE,
|
||||
0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
const float DISTANT_BORDER[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, DISTANT_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
_shadowFramebufferObject->bind();
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _shadowDepthTextureID, 0);
|
||||
_shadowFramebufferObject->release();
|
||||
_shadowFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(SHADOW_MAP_SIZE));
|
||||
|
||||
_shadowTexture = _shadowFramebuffer->getDepthStencilBuffer();
|
||||
}
|
||||
return _shadowFramebufferObject;
|
||||
return _shadowFramebuffer;
|
||||
}
|
||||
|
||||
GLuint TextureCache::getShadowDepthTextureID() {
|
||||
// ensure that the shadow framebuffer object is initialized before returning the depth texture id
|
||||
getShadowFramebufferObject();
|
||||
return _shadowDepthTextureID;
|
||||
getShadowFramebuffer();
|
||||
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 (_primaryFramebufferObject && _primaryFramebufferObject->size() != size) {
|
||||
delete _primaryFramebufferObject;
|
||||
_primaryFramebufferObject = NULL;
|
||||
glDeleteTextures(1, &_primaryDepthTextureID);
|
||||
glDeleteTextures(1, &_primaryNormalTextureID);
|
||||
glDeleteTextures(1, &_primarySpecularTextureID);
|
||||
}
|
||||
if (_secondaryFramebufferObject && _secondaryFramebufferObject->size() != size) {
|
||||
delete _secondaryFramebufferObject;
|
||||
_secondaryFramebufferObject = NULL;
|
||||
}
|
||||
if (_tertiaryFramebufferObject && _tertiaryFramebufferObject->size() != size) {
|
||||
delete _tertiaryFramebufferObject;
|
||||
_tertiaryFramebufferObject = NULL;
|
||||
if (_frameBufferSize != size) {
|
||||
_primaryFramebuffer.reset();
|
||||
_primaryColorTexture.reset();
|
||||
_primaryDepthTexture.reset();
|
||||
_primaryNormalTexture.reset();
|
||||
_primarySpecularTexture.reset();
|
||||
|
||||
_secondaryFramebuffer.reset();
|
||||
|
||||
_tertiaryFramebuffer.reset();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -359,17 +323,6 @@ void TextureCache::associateWithWidget(QGLWidget* widget) {
|
|||
_associatedWidget->installEventFilter(this);
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* TextureCache::createFramebufferObject() {
|
||||
QOpenGLFramebufferObject* fbo = new QOpenGLFramebufferObject(_frameBufferSize);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, fbo->texture());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return fbo;
|
||||
}
|
||||
|
||||
Texture::Texture() {
|
||||
}
|
||||
|
||||
|
@ -559,7 +512,7 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo
|
|||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height()));
|
||||
_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
_gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
_gpuTexture->autoGenerateMips(-1);
|
||||
}
|
||||
|
@ -598,7 +551,7 @@ QSharedPointer<Texture> DilatableNetworkTexture::getDilatedTexture(float dilatio
|
|||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::BGRA));
|
||||
}
|
||||
texture->_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, dilatedImage.width(), dilatedImage.height()));
|
||||
texture->_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, dilatedImage.width(), dilatedImage.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
texture->_gpuTexture->assignStoredMip(0, formatMip, dilatedImage.byteCount(), dilatedImage.constBits());
|
||||
texture->_gpuTexture->autoGenerateMips(-1);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <gpu/GPUConfig.h>
|
||||
#include <gpu/Texture.h>
|
||||
#include <gpu/Framebuffer.h>
|
||||
|
||||
#include <QImage>
|
||||
#include <QMap>
|
||||
|
@ -22,8 +23,6 @@
|
|||
#include <DependencyManager.h>
|
||||
#include <ResourceCache.h>
|
||||
|
||||
class QOpenGLFramebufferObject;
|
||||
|
||||
class NetworkTexture;
|
||||
|
||||
typedef QSharedPointer<NetworkTexture> NetworkTexturePointer;
|
||||
|
@ -60,11 +59,17 @@ public:
|
|||
|
||||
/// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is
|
||||
/// used for scene rendering.
|
||||
QOpenGLFramebufferObject* getPrimaryFramebufferObject();
|
||||
|
||||
gpu::FramebufferPointer getPrimaryFramebuffer();
|
||||
|
||||
gpu::TexturePointer getPrimaryDepthTexture();
|
||||
gpu::TexturePointer getPrimaryColorTexture();
|
||||
gpu::TexturePointer getPrimaryNormalTexture();
|
||||
gpu::TexturePointer getPrimarySpecularTexture();
|
||||
|
||||
/// Returns the ID of the primary framebuffer object's depth texture. This contains the Z buffer used in rendering.
|
||||
GLuint getPrimaryDepthTextureID();
|
||||
|
||||
GLuint getPrimaryColorTextureID();
|
||||
|
||||
/// Returns the ID of the primary framebuffer object's normal texture.
|
||||
GLuint getPrimaryNormalTextureID();
|
||||
|
||||
|
@ -76,15 +81,16 @@ public:
|
|||
|
||||
/// Returns a pointer to the secondary framebuffer object, used as an additional render target when performing full
|
||||
/// screen effects.
|
||||
QOpenGLFramebufferObject* getSecondaryFramebufferObject();
|
||||
gpu::FramebufferPointer getSecondaryFramebuffer();
|
||||
|
||||
/// Returns a pointer to the tertiary framebuffer object, used as an additional render target when performing full
|
||||
/// screen effects.
|
||||
QOpenGLFramebufferObject* getTertiaryFramebufferObject();
|
||||
|
||||
/// Returns a pointer to the framebuffer object used to render shadow maps.
|
||||
QOpenGLFramebufferObject* getShadowFramebufferObject();
|
||||
gpu::FramebufferPointer getTertiaryFramebuffer();
|
||||
|
||||
/// Returns the framebuffer object used to render shadow maps;
|
||||
gpu::FramebufferPointer getShadowFramebuffer();
|
||||
|
||||
|
||||
/// Returns the ID of the shadow framebuffer object's depth texture.
|
||||
GLuint getShadowDepthTextureID();
|
||||
|
||||
|
@ -99,24 +105,26 @@ private:
|
|||
TextureCache();
|
||||
virtual ~TextureCache();
|
||||
friend class DilatableNetworkTexture;
|
||||
|
||||
QOpenGLFramebufferObject* createFramebufferObject();
|
||||
|
||||
gpu::TexturePointer _permutationNormalTexture;
|
||||
gpu::TexturePointer _whiteTexture;
|
||||
gpu::TexturePointer _blueTexture;
|
||||
|
||||
|
||||
QHash<QUrl, QWeakPointer<NetworkTexture> > _dilatableNetworkTextures;
|
||||
|
||||
GLuint _primaryDepthTextureID;
|
||||
GLuint _primaryNormalTextureID;
|
||||
GLuint _primarySpecularTextureID;
|
||||
QOpenGLFramebufferObject* _primaryFramebufferObject;
|
||||
QOpenGLFramebufferObject* _secondaryFramebufferObject;
|
||||
QOpenGLFramebufferObject* _tertiaryFramebufferObject;
|
||||
|
||||
QOpenGLFramebufferObject* _shadowFramebufferObject;
|
||||
GLuint _shadowDepthTextureID;
|
||||
|
||||
gpu::TexturePointer _primaryDepthTexture;
|
||||
gpu::TexturePointer _primaryColorTexture;
|
||||
gpu::TexturePointer _primaryNormalTexture;
|
||||
gpu::TexturePointer _primarySpecularTexture;
|
||||
gpu::FramebufferPointer _primaryFramebuffer;
|
||||
void createPrimaryFramebuffer();
|
||||
|
||||
gpu::FramebufferPointer _secondaryFramebuffer;
|
||||
gpu::FramebufferPointer _tertiaryFramebuffer;
|
||||
|
||||
gpu::FramebufferPointer _shadowFramebuffer;
|
||||
gpu::TexturePointer _shadowTexture;
|
||||
|
||||
QSize _frameBufferSize;
|
||||
QGLWidget* _associatedWidget;
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AudioScriptingInterface.h"
|
||||
|
||||
#include "ScriptAudioInjector.h"
|
||||
#include "ScriptEngineLogging.h"
|
||||
#include "AudioScriptingInterface.h"
|
||||
|
||||
void registerAudioMetaTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue);
|
||||
|
@ -69,3 +70,23 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const Audi
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioScriptingInterface::injectGeneratedNoise(bool inject) {
|
||||
if (_localAudioInterface) {
|
||||
_localAudioInterface->enableAudioSourceInject(inject);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioScriptingInterface::selectPinkNoise() {
|
||||
if (_localAudioInterface) {
|
||||
_localAudioInterface->selectAudioSourcePinkNoise();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioScriptingInterface::selectSine440() {
|
||||
if (_localAudioInterface) {
|
||||
_localAudioInterface->selectAudioSourceSine440();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@ protected:
|
|||
// this method is protected to stop C++ callers from calling, but invokable from script
|
||||
Q_INVOKABLE ScriptAudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions());
|
||||
|
||||
Q_INVOKABLE void injectGeneratedNoise(bool inject);
|
||||
Q_INVOKABLE void selectPinkNoise();
|
||||
Q_INVOKABLE void selectSine440();
|
||||
|
||||
signals:
|
||||
void mutedByMixer();
|
||||
void environmentMuted();
|
||||
|
|
|
@ -37,12 +37,6 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
|||
_halfExtents = glm::vec3(radius);
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_CONVEX_HULL:
|
||||
_url = QUrl(url);
|
||||
// halfExtents aren't used by convex-hull or compound convex-hull except as part of
|
||||
// the generation of the key for the ShapeManager.
|
||||
_halfExtents = halfExtents;
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND:
|
||||
_url = QUrl(url);
|
||||
_halfExtents = halfExtents;
|
||||
|
@ -78,12 +72,8 @@ void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) {
|
|||
}
|
||||
|
||||
void ShapeInfo::setConvexHulls(const QVector<QVector<glm::vec3>>& points) {
|
||||
if (points.size() == 1) {
|
||||
_type = SHAPE_TYPE_CONVEX_HULL;
|
||||
} else {
|
||||
_type = SHAPE_TYPE_COMPOUND;
|
||||
}
|
||||
_points = points;
|
||||
_type = (_points.size() > 0) ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
|
@ -95,6 +85,14 @@ void ShapeInfo::setCapsuleY(float radius, float halfHeight) {
|
|||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
uint32_t ShapeInfo::getNumSubShapes() const {
|
||||
if (_type == SHAPE_TYPE_NONE) {
|
||||
return 0;
|
||||
} else if (_type == SHAPE_TYPE_COMPOUND) {
|
||||
return _points.size();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
float ShapeInfo::computeVolume() const {
|
||||
const float DEFAULT_VOLUME = 1.0f;
|
||||
float volume = DEFAULT_VOLUME;
|
||||
|
|
|
@ -24,7 +24,6 @@ enum ShapeType {
|
|||
SHAPE_TYPE_BOX,
|
||||
SHAPE_TYPE_SPHERE,
|
||||
SHAPE_TYPE_ELLIPSOID,
|
||||
SHAPE_TYPE_CONVEX_HULL,
|
||||
SHAPE_TYPE_PLANE,
|
||||
SHAPE_TYPE_COMPOUND,
|
||||
SHAPE_TYPE_CAPSULE_X,
|
||||
|
@ -52,6 +51,7 @@ public:
|
|||
const glm::vec3& getHalfExtents() const { return _halfExtents; }
|
||||
|
||||
const QVector<QVector<glm::vec3>>& getPoints() const { return _points; }
|
||||
uint32_t getNumSubShapes() const;
|
||||
|
||||
void clearPoints () { _points.clear(); }
|
||||
void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; }
|
||||
|
|
|
@ -147,9 +147,7 @@ void ShapeInfoTests::testBoxShape() {
|
|||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: NULL Box shape" << std::endl;
|
||||
}
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
|
@ -172,9 +170,7 @@ void ShapeInfoTests::testSphereShape() {
|
|||
|
||||
btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info);
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
|
@ -198,9 +194,7 @@ void ShapeInfoTests::testCylinderShape() {
|
|||
|
||||
btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info);
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
|
@ -225,9 +219,7 @@ void ShapeInfoTests::testCapsuleShape() {
|
|||
|
||||
btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info);
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
|
|
|
@ -187,9 +187,7 @@ void ShapeManagerTests::addBoxShape() {
|
|||
ShapeManager shapeManager;
|
||||
btCollisionShape* shape = shapeManager.getShape(info);
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
|
||||
if (shape != otherShape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
|
@ -205,9 +203,7 @@ void ShapeManagerTests::addSphereShape() {
|
|||
ShapeManager shapeManager;
|
||||
btCollisionShape* shape = shapeManager.getShape(info);
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
|
||||
if (shape != otherShape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
|
@ -225,9 +221,7 @@ void ShapeManagerTests::addCylinderShape() {
|
|||
ShapeManager shapeManager;
|
||||
btCollisionShape* shape = shapeManager.getShape(info);
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
|
||||
if (shape != otherShape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
|
@ -246,9 +240,7 @@ void ShapeManagerTests::addCapsuleShape() {
|
|||
ShapeManager shapeManager;
|
||||
btCollisionShape* shape = shapeManager.getShape(info);
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
|
||||
if (shape != otherShape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
|
|
Loading…
Reference in a new issue