mirror of
https://github.com/overte-org/overte.git
synced 2025-04-10 19:29:07 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into tablet-webView2.0
This commit is contained in:
commit
b10f491c6e
48 changed files with 1017 additions and 575 deletions
|
@ -187,7 +187,7 @@ void AvatarMixer::start() {
|
|||
|
||||
|
||||
// NOTE: nodeData->getAvatar() might be side effected, must be called when access to node/nodeData
|
||||
// is guarenteed to not be accessed by other thread
|
||||
// is guaranteed to not be accessed by other thread
|
||||
void AvatarMixer::manageDisplayName(const SharedNodePointer& node) {
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData());
|
||||
if (nodeData && nodeData->getAvatarSessionDisplayNameMustChange()) {
|
||||
|
|
|
@ -49,7 +49,7 @@ private:
|
|||
bool _stop { false };
|
||||
};
|
||||
|
||||
// Slave pool for audio mixers
|
||||
// Slave pool for avatar mixers
|
||||
// AvatarMixerSlavePool is not thread-safe! It should be instantiated and used from a single thread.
|
||||
class AvatarMixerSlavePool {
|
||||
using Queue = tbb::concurrent_queue<SharedNodePointer>;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4 as Controls
|
||||
|
||||
import "../../qml/menus"
|
||||
import "../../qml/controls-uit"
|
||||
import "../../qml/styles-uit"
|
||||
|
||||
|
|
|
@ -180,6 +180,7 @@
|
|||
#include "FrameTimingsScriptingInterface.h"
|
||||
#include <GPUIdent.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <src/scripting/LimitlessVoiceRecognitionScriptingInterface.h>
|
||||
#include <EntityScriptClient.h>
|
||||
#include <ModelScriptingInterface.h>
|
||||
|
||||
|
@ -522,7 +523,9 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
DependencyManager::set<OffscreenQmlSurfaceCache>();
|
||||
DependencyManager::set<EntityScriptClient>();
|
||||
DependencyManager::set<EntityScriptServerLogClient>();
|
||||
DependencyManager::set<LimitlessVoiceRecognitionScriptingInterface>();
|
||||
DependencyManager::set<OctreeStatsProvider>(nullptr, qApp->getOcteeSceneStats());
|
||||
|
||||
return previousSessionCrashed;
|
||||
}
|
||||
|
||||
|
@ -550,7 +553,7 @@ const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f;
|
|||
const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true;
|
||||
const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false;
|
||||
const bool DEFAULT_TABLET_VISIBLE_TO_OTHERS = false;
|
||||
const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = true;
|
||||
const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false;
|
||||
|
||||
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) :
|
||||
QApplication(argc, argv),
|
||||
|
@ -4572,6 +4575,8 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
|
||||
AnimDebugDraw::getInstance().update();
|
||||
|
||||
DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>()->update();
|
||||
}
|
||||
|
||||
void Application::sendAvatarViewFrustum() {
|
||||
|
@ -5518,6 +5523,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>().data());
|
||||
|
||||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||
scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine, steamClient.get()));
|
||||
}
|
||||
|
|
91
interface/src/scripting/LimitlessConnection.cpp
Normal file
91
interface/src/scripting/LimitlessConnection.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <src/InterfaceLogging.h>
|
||||
#include <src/ui/AvatarInputs.h>
|
||||
#include "LimitlessConnection.h"
|
||||
#include "LimitlessVoiceRecognitionScriptingInterface.h"
|
||||
|
||||
LimitlessConnection::LimitlessConnection() :
|
||||
_streamingAudioForTranscription(false)
|
||||
{
|
||||
}
|
||||
|
||||
void LimitlessConnection::startListening(QString authCode) {
|
||||
_transcribeServerSocket.reset(new QTcpSocket(this));
|
||||
connect(_transcribeServerSocket.get(), &QTcpSocket::readyRead, this,
|
||||
&LimitlessConnection::transcriptionReceived);
|
||||
connect(_transcribeServerSocket.get(), &QTcpSocket::disconnected, this, [this](){stopListening();});
|
||||
|
||||
static const auto host = "gserv_devel.studiolimitless.com";
|
||||
_transcribeServerSocket->connectToHost(host, 1407);
|
||||
_transcribeServerSocket->waitForConnected();
|
||||
QString requestHeader = QString::asprintf("Authorization: %s\r\nfs: %i\r\n",
|
||||
authCode.toLocal8Bit().data(), AudioConstants::SAMPLE_RATE);
|
||||
qCDebug(interfaceapp) << "Sending Limitless Audio Stream Request: " << requestHeader;
|
||||
_transcribeServerSocket->write(requestHeader.toLocal8Bit());
|
||||
_transcribeServerSocket->waitForBytesWritten();
|
||||
}
|
||||
|
||||
void LimitlessConnection::stopListening() {
|
||||
emit onFinishedSpeaking(_currentTranscription);
|
||||
_streamingAudioForTranscription = false;
|
||||
_currentTranscription = "";
|
||||
if (!isConnected())
|
||||
return;
|
||||
_transcribeServerSocket->close();
|
||||
disconnect(_transcribeServerSocket.get(), &QTcpSocket::readyRead, this,
|
||||
&LimitlessConnection::transcriptionReceived);
|
||||
_transcribeServerSocket.release()->deleteLater();
|
||||
disconnect(DependencyManager::get<AudioClient>().data(), &AudioClient::inputReceived, this,
|
||||
&LimitlessConnection::audioInputReceived);
|
||||
qCDebug(interfaceapp) << "Connection to Limitless Voice Server closed.";
|
||||
}
|
||||
|
||||
void LimitlessConnection::audioInputReceived(const QByteArray& inputSamples) {
|
||||
if (isConnected()) {
|
||||
_transcribeServerSocket->write(inputSamples.data(), inputSamples.size());
|
||||
_transcribeServerSocket->waitForBytesWritten();
|
||||
}
|
||||
}
|
||||
|
||||
void LimitlessConnection::transcriptionReceived() {
|
||||
while (_transcribeServerSocket && _transcribeServerSocket->bytesAvailable() > 0) {
|
||||
const QByteArray data = _transcribeServerSocket->readAll();
|
||||
_serverDataBuffer.append(data);
|
||||
int begin = _serverDataBuffer.indexOf('<');
|
||||
int end = _serverDataBuffer.indexOf('>');
|
||||
while (begin > -1 && end > -1) {
|
||||
const int len = end - begin;
|
||||
const QByteArray serverMessage = _serverDataBuffer.mid(begin+1, len-1);
|
||||
if (serverMessage.contains("1407")) {
|
||||
qCDebug(interfaceapp) << "Limitless Speech Server denied the request.";
|
||||
// Don't spam the server with further false requests please.
|
||||
DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>()->setListeningToVoice(true);
|
||||
stopListening();
|
||||
return;
|
||||
} else if (serverMessage.contains("1408")) {
|
||||
qCDebug(interfaceapp) << "Limitless Audio request authenticated!";
|
||||
_serverDataBuffer.clear();
|
||||
connect(DependencyManager::get<AudioClient>().data(), &AudioClient::inputReceived, this,
|
||||
&LimitlessConnection::audioInputReceived);
|
||||
return;
|
||||
}
|
||||
QJsonObject json = QJsonDocument::fromJson(serverMessage.data()).object();
|
||||
_serverDataBuffer.remove(begin, len+1);
|
||||
_currentTranscription = json["alternatives"].toArray()[0].toObject()["transcript"].toString();
|
||||
emit onReceivedTranscription(_currentTranscription);
|
||||
if (json["isFinal"] == true) {
|
||||
qCDebug(interfaceapp) << "Final transcription: " << _currentTranscription;
|
||||
stopListening();
|
||||
return;
|
||||
}
|
||||
begin = _serverDataBuffer.indexOf('<');
|
||||
end = _serverDataBuffer.indexOf('>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LimitlessConnection::isConnected() const {
|
||||
return _transcribeServerSocket.get() && _transcribeServerSocket->isWritable()
|
||||
&& _transcribeServerSocket->state() != QAbstractSocket::SocketState::UnconnectedState;
|
||||
}
|
44
interface/src/scripting/LimitlessConnection.h
Normal file
44
interface/src/scripting/LimitlessConnection.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// SpeechRecognitionScriptingInterface.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Trevor Berninger on 3/24/17.
|
||||
// Copyright 2017 Limitless ltd.
|
||||
//
|
||||
// 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_LimitlessConnection_h
|
||||
#define hifi_LimitlessConnection_h
|
||||
|
||||
#include <AudioClient.h>
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
|
||||
class LimitlessConnection : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LimitlessConnection();
|
||||
|
||||
Q_INVOKABLE void startListening(QString authCode);
|
||||
Q_INVOKABLE void stopListening();
|
||||
|
||||
std::atomic<bool> _streamingAudioForTranscription;
|
||||
|
||||
signals:
|
||||
void onReceivedTranscription(QString speech);
|
||||
void onFinishedSpeaking(QString speech);
|
||||
|
||||
private:
|
||||
void transcriptionReceived();
|
||||
void audioInputReceived(const QByteArray& inputSamples);
|
||||
|
||||
bool isConnected() const;
|
||||
|
||||
std::unique_ptr<QTcpSocket> _transcribeServerSocket;
|
||||
QByteArray _serverDataBuffer;
|
||||
QString _currentTranscription;
|
||||
};
|
||||
|
||||
#endif //hifi_LimitlessConnection_h
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// SpeechRecognitionScriptingInterface.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Trevor Berninger on 3/20/17.
|
||||
// Copyright 2017 Limitless ltd.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <src/InterfaceLogging.h>
|
||||
#include <src/ui/AvatarInputs.h>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include "LimitlessVoiceRecognitionScriptingInterface.h"
|
||||
|
||||
const float LimitlessVoiceRecognitionScriptingInterface::_audioLevelThreshold = 0.33f;
|
||||
const int LimitlessVoiceRecognitionScriptingInterface::_voiceTimeoutDuration = 2000;
|
||||
|
||||
LimitlessVoiceRecognitionScriptingInterface::LimitlessVoiceRecognitionScriptingInterface() :
|
||||
_shouldStartListeningForVoice(false)
|
||||
{
|
||||
_voiceTimer.setSingleShot(true);
|
||||
connect(&_voiceTimer, &QTimer::timeout, this, &LimitlessVoiceRecognitionScriptingInterface::voiceTimeout);
|
||||
connect(&_connection, &LimitlessConnection::onReceivedTranscription, this, [this](QString transcription){emit onReceivedTranscription(transcription);});
|
||||
connect(&_connection, &LimitlessConnection::onFinishedSpeaking, this, [this](QString transcription){emit onFinishedSpeaking(transcription);});
|
||||
_connection.moveToThread(&_connectionThread);
|
||||
_connectionThread.setObjectName("Limitless Connection");
|
||||
_connectionThread.start();
|
||||
}
|
||||
|
||||
void LimitlessVoiceRecognitionScriptingInterface::update() {
|
||||
const float audioLevel = AvatarInputs::getInstance()->loudnessToAudioLevel(DependencyManager::get<AudioClient>()->getAudioAverageInputLoudness());
|
||||
|
||||
if (_shouldStartListeningForVoice) {
|
||||
if (_connection._streamingAudioForTranscription) {
|
||||
if (audioLevel > _audioLevelThreshold) {
|
||||
if (_voiceTimer.isActive()) {
|
||||
_voiceTimer.stop();
|
||||
}
|
||||
} else if (!_voiceTimer.isActive()){
|
||||
_voiceTimer.start(_voiceTimeoutDuration);
|
||||
}
|
||||
} else if (audioLevel > _audioLevelThreshold) {
|
||||
// to make sure invoke doesn't get called twice before the method actually gets called
|
||||
_connection._streamingAudioForTranscription = true;
|
||||
QMetaObject::invokeMethod(&_connection, "startListening", Q_ARG(QString, authCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LimitlessVoiceRecognitionScriptingInterface::setListeningToVoice(bool listening) {
|
||||
_shouldStartListeningForVoice = listening;
|
||||
}
|
||||
|
||||
void LimitlessVoiceRecognitionScriptingInterface::setAuthKey(QString key) {
|
||||
authCode = key;
|
||||
}
|
||||
|
||||
void LimitlessVoiceRecognitionScriptingInterface::voiceTimeout() {
|
||||
if (_connection._streamingAudioForTranscription) {
|
||||
QMetaObject::invokeMethod(&_connection, "stopListening");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// SpeechRecognitionScriptingInterface.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Trevor Berninger on 3/20/17.
|
||||
// Copyright 2017 Limitless ltd.
|
||||
//
|
||||
// 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_SpeechRecognitionScriptingInterface_h
|
||||
#define hifi_SpeechRecognitionScriptingInterface_h
|
||||
|
||||
#include <AudioClient.h>
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
#include "LimitlessConnection.h"
|
||||
|
||||
class LimitlessVoiceRecognitionScriptingInterface : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LimitlessVoiceRecognitionScriptingInterface();
|
||||
|
||||
void update();
|
||||
|
||||
QString authCode;
|
||||
|
||||
public slots:
|
||||
void setListeningToVoice(bool listening);
|
||||
void setAuthKey(QString key);
|
||||
|
||||
signals:
|
||||
void onReceivedTranscription(QString speech);
|
||||
void onFinishedSpeaking(QString speech);
|
||||
|
||||
private:
|
||||
|
||||
bool _shouldStartListeningForVoice;
|
||||
static const float _audioLevelThreshold;
|
||||
static const int _voiceTimeoutDuration;
|
||||
|
||||
QTimer _voiceTimer;
|
||||
QThread _connectionThread;
|
||||
LimitlessConnection _connection;
|
||||
|
||||
void voiceTimeout();
|
||||
};
|
||||
|
||||
#endif //hifi_SpeechRecognitionScriptingInterface_h
|
|
@ -85,7 +85,6 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
|||
renderAudioScope(renderArgs); // audio scope in the very back - NOTE: this is the debug audio scope, not the VU meter
|
||||
renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope
|
||||
renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture, and the text overlays from scripts
|
||||
renderStatsAndLogs(renderArgs); // currently renders nothing
|
||||
});
|
||||
|
||||
renderArgs->_batch = nullptr; // so future users of renderArgs don't try to use our batch
|
||||
|
@ -159,27 +158,6 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
|
|||
qApp->getOverlays().renderHUD(renderArgs);
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
|
||||
|
||||
// Display stats and log text onscreen
|
||||
|
||||
// Determine whether to compute timing details
|
||||
|
||||
/*
|
||||
// Show on-screen msec timer
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
|
||||
QString frameTimer = QString("%1\n").arg((int)(mSecsNow % 1000));
|
||||
int timerBottom =
|
||||
(Menu::getInstance()->isOptionChecked(MenuOption::Stats))
|
||||
? 80 : 20;
|
||||
drawText(canvasSize.x - 100, canvasSize.y - timerBottom,
|
||||
0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderArgs) {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
static std::once_flag once;
|
||||
|
@ -229,13 +207,13 @@ void ApplicationOverlay::buildFramebufferObject() {
|
|||
auto width = uiSize.x;
|
||||
auto height = uiSize.y;
|
||||
if (!_overlayFramebuffer->getDepthStencilBuffer()) {
|
||||
auto overlayDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(DEPTH_FORMAT, width, height, DEFAULT_SAMPLER));
|
||||
auto overlayDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(DEPTH_FORMAT, width, height, gpu::Texture::SINGLE_MIP, DEFAULT_SAMPLER));
|
||||
_overlayFramebuffer->setDepthStencilBuffer(overlayDepthTexture, DEPTH_FORMAT);
|
||||
}
|
||||
|
||||
if (!_overlayFramebuffer->getRenderBuffer(0)) {
|
||||
const gpu::Sampler OVERLAY_SAMPLER(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP);
|
||||
auto colorBuffer = gpu::TexturePointer(gpu::Texture::createRenderBuffer(COLOR_FORMAT, width, height, OVERLAY_SAMPLER));
|
||||
auto colorBuffer = gpu::TexturePointer(gpu::Texture::createRenderBuffer(COLOR_FORMAT, width, height, gpu::Texture::SINGLE_MIP, OVERLAY_SAMPLER));
|
||||
_overlayFramebuffer->setRenderBuffer(0, colorBuffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,24 +62,13 @@ AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) {
|
|||
} \
|
||||
}
|
||||
|
||||
void AvatarInputs::update() {
|
||||
if (!Menu::getInstance()) {
|
||||
return;
|
||||
}
|
||||
AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking));
|
||||
AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking));
|
||||
AI_UPDATE(isHMD, qApp->isHMDMode());
|
||||
|
||||
AI_UPDATE_WRITABLE(showAudioTools, Menu::getInstance()->isOptionChecked(MenuOption::AudioTools));
|
||||
|
||||
auto audioIO = DependencyManager::get<AudioClient>();
|
||||
float AvatarInputs::loudnessToAudioLevel(float loudness) {
|
||||
const float AUDIO_METER_AVERAGING = 0.5;
|
||||
const float LOG2 = log(2.0f);
|
||||
const float METER_LOUDNESS_SCALE = 2.8f / 5.0f;
|
||||
const float LOG2_LOUDNESS_FLOOR = 11.0f;
|
||||
float audioLevel = 0.0f;
|
||||
auto audio = DependencyManager::get<AudioClient>();
|
||||
float loudness = audio->getLastInputLoudness() + 1.0f;
|
||||
loudness += 1.0f;
|
||||
|
||||
_trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.0f - AUDIO_METER_AVERAGING) * loudness;
|
||||
|
||||
|
@ -93,6 +82,24 @@ void AvatarInputs::update() {
|
|||
if (audioLevel > 1.0f) {
|
||||
audioLevel = 1.0;
|
||||
}
|
||||
return audioLevel;
|
||||
}
|
||||
|
||||
void AvatarInputs::update() {
|
||||
if (!Menu::getInstance()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking));
|
||||
AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking));
|
||||
AI_UPDATE(isHMD, qApp->isHMDMode());
|
||||
|
||||
AI_UPDATE_WRITABLE(showAudioTools, Menu::getInstance()->isOptionChecked(MenuOption::AudioTools));
|
||||
|
||||
auto audioIO = DependencyManager::get<AudioClient>();
|
||||
|
||||
const float audioLevel = loudnessToAudioLevel(DependencyManager::get<AudioClient>()->getLastInputLoudness());
|
||||
|
||||
AI_UPDATE_FLOAT(audioLevel, audioLevel, 0.01f);
|
||||
AI_UPDATE(audioClipping, ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f)));
|
||||
AI_UPDATE(audioMuted, audioIO->isMuted());
|
||||
|
|
|
@ -34,6 +34,7 @@ class AvatarInputs : public QQuickItem {
|
|||
|
||||
public:
|
||||
static AvatarInputs* getInstance();
|
||||
float loudnessToAudioLevel(float loudness);
|
||||
AvatarInputs(QQuickItem* parent = nullptr);
|
||||
void update();
|
||||
bool showAudioTools() const { return _showAudioTools; }
|
||||
|
|
|
@ -350,11 +350,15 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) {
|
|||
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi);
|
||||
QPointF windowPoint(windowPos.x, windowPos.y);
|
||||
|
||||
if (event.getButtons() == PointerEvent::NoButtons && event.getType() == PointerEvent::Move) {
|
||||
// Forward a mouse move event to the Web surface.
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
// Forward a mouse move event to the Web surface so that hover events are generated.
|
||||
// Must send a mouse move event that matches up with touch move event in order for scroll bars to work.
|
||||
|
||||
// Scroll bar dragging is a bit unstable in the tablet (content can jump up and down at times).
|
||||
// This may be improved in Qt 5.8. Release notes: "Cleaned up touch and mouse event delivery".
|
||||
|
||||
QMouseEvent* mouseEvent = new QMouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), mouseEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) {
|
||||
|
|
|
@ -1495,6 +1495,9 @@ void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityC
|
|||
setAvatarEntityData(identity.avatarEntityData);
|
||||
identityChanged = true;
|
||||
}
|
||||
// flag this avatar as non-stale by updating _averageBytesReceived
|
||||
const int BOGUS_NUM_BYTES = 1;
|
||||
_averageBytesReceived.updateAverage(BOGUS_NUM_BYTES);
|
||||
}
|
||||
|
||||
QByteArray AvatarData::identityByteArray() const {
|
||||
|
|
|
@ -356,15 +356,16 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
|
||||
cursorData.texture.reset(
|
||||
gpu::Texture::createStrict(
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Texture::MAX_NUM_MIPS,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
cursorData.texture->setSource("cursor texture");
|
||||
auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
|
||||
cursorData.texture->setUsage(usage.build());
|
||||
cursorData.texture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
cursorData.texture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
cursorData.texture->autoGenerateMips(-1);
|
||||
cursorData.texture->setAutoGenerateMips(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -299,12 +299,13 @@ void HmdDisplayPlugin::internalPresent() {
|
|||
gpu::Texture::createStrict(
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Texture::MAX_NUM_MIPS,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
_previewTexture->setSource("HMD Preview Texture");
|
||||
_previewTexture->setUsage(gpu::Texture::Usage::Builder().withColor().build());
|
||||
_previewTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
_previewTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
_previewTexture->autoGenerateMips(-1);
|
||||
_previewTexture->setAutoGenerateMips(true);
|
||||
}
|
||||
|
||||
auto viewport = getViewportForSourceSize(uvec2(_previewTexture->getDimensions()));
|
||||
|
|
|
@ -229,7 +229,7 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) {
|
|||
|
||||
_resource._textures[slot] = resourceTexture;
|
||||
|
||||
_stats._RSAmountTextureMemoryBounded += object->size();
|
||||
_stats._RSAmountTextureMemoryBounded += (int) object->size();
|
||||
|
||||
} else {
|
||||
releaseResourceTexture(slot);
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
static const GLenum WRAP_MODES[Sampler::NUM_WRAP_MODES];
|
||||
|
||||
protected:
|
||||
virtual uint32 size() const = 0;
|
||||
virtual Size size() const = 0;
|
||||
virtual void generateMips() const = 0;
|
||||
|
||||
GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id);
|
||||
|
@ -57,7 +57,7 @@ public:
|
|||
protected:
|
||||
GLExternalTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id);
|
||||
void generateMips() const override {}
|
||||
uint32 size() const override { return 0; }
|
||||
Size size() const override { return 0; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -40,30 +40,59 @@ public:
|
|||
|
||||
class GL41Texture : public GLTexture {
|
||||
using Parent = GLTexture;
|
||||
static GLuint allocate();
|
||||
|
||||
public:
|
||||
~GL41Texture();
|
||||
|
||||
private:
|
||||
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer);
|
||||
|
||||
void generateMips() const override;
|
||||
uint32 size() const override;
|
||||
|
||||
friend class GL41Backend;
|
||||
const Stamp _storageStamp;
|
||||
mutable Stamp _contentStamp { 0 };
|
||||
mutable Stamp _samplerStamp { 0 };
|
||||
const uint32 _size;
|
||||
static GLuint allocate(const Texture& texture);
|
||||
protected:
|
||||
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
|
||||
void generateMips() const override;
|
||||
void copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face) const;
|
||||
void copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum format, GLenum type, const void* sourcePointer) const;
|
||||
virtual void syncSampler() const;
|
||||
|
||||
|
||||
bool isOutdated() const;
|
||||
void withPreservedTexture(std::function<void()> f) const;
|
||||
void syncContent() const;
|
||||
void syncSampler() const;
|
||||
};
|
||||
|
||||
//
|
||||
// Textures that have fixed allocation sizes and cannot be managed at runtime
|
||||
//
|
||||
|
||||
class GL41FixedAllocationTexture : public GL41Texture {
|
||||
using Parent = GL41Texture;
|
||||
friend class GL41Backend;
|
||||
|
||||
public:
|
||||
GL41FixedAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
|
||||
~GL41FixedAllocationTexture();
|
||||
|
||||
protected:
|
||||
Size size() const override { return _size; }
|
||||
void allocateStorage() const;
|
||||
void syncSampler() const override;
|
||||
const Size _size { 0 };
|
||||
};
|
||||
|
||||
class GL41AttachmentTexture : public GL41FixedAllocationTexture {
|
||||
using Parent = GL41FixedAllocationTexture;
|
||||
friend class GL41Backend;
|
||||
protected:
|
||||
GL41AttachmentTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
|
||||
~GL41AttachmentTexture();
|
||||
};
|
||||
|
||||
class GL41StrictResourceTexture : public GL41FixedAllocationTexture {
|
||||
using Parent = GL41FixedAllocationTexture;
|
||||
friend class GL41Backend;
|
||||
protected:
|
||||
GL41StrictResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
|
||||
};
|
||||
|
||||
class GL41ResourceTexture : public GL41FixedAllocationTexture {
|
||||
using Parent = GL41FixedAllocationTexture;
|
||||
friend class GL41Backend;
|
||||
protected:
|
||||
GL41ResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
|
||||
~GL41ResourceTexture();
|
||||
};
|
||||
|
||||
protected:
|
||||
GLuint getFramebufferID(const FramebufferPointer& framebuffer) override;
|
||||
|
|
|
@ -19,20 +19,11 @@ using namespace gpu;
|
|||
using namespace gpu::gl;
|
||||
using namespace gpu::gl41;
|
||||
|
||||
using GL41TexelFormat = GLTexelFormat;
|
||||
using GL41Texture = GL41Backend::GL41Texture;
|
||||
|
||||
GLuint GL41Texture::allocate() {
|
||||
Backend::incrementTextureGPUCount();
|
||||
GLuint result;
|
||||
glGenTextures(1, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texturePointer) {
|
||||
if (!texturePointer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Texture& texture = *texturePointer;
|
||||
if (TextureUsageType::EXTERNAL == texture.getUsageType()) {
|
||||
return Parent::syncGPUObject(texturePointer);
|
||||
|
@ -43,90 +34,58 @@ GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texturePointer) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// If the object hasn't been created, or the object definition is out of date, drop and re-create
|
||||
GL41Texture* object = Backend::getGPUObject<GL41Texture>(texture);
|
||||
if (!object || object->_storageStamp < texture.getStamp()) {
|
||||
// This automatically any previous texture
|
||||
object = new GL41Texture(shared_from_this(), texture);
|
||||
}
|
||||
if (!object) {
|
||||
switch (texture.getUsageType()) {
|
||||
case TextureUsageType::RENDERBUFFER:
|
||||
object = new GL41AttachmentTexture(shared_from_this(), texture);
|
||||
break;
|
||||
|
||||
// FIXME internalize to GL41Texture 'sync' function
|
||||
if (object->isOutdated()) {
|
||||
object->withPreservedTexture([&] {
|
||||
if (object->_contentStamp <= texture.getDataStamp()) {
|
||||
// FIXME implement synchronous texture transfer here
|
||||
object->syncContent();
|
||||
case TextureUsageType::STRICT_RESOURCE:
|
||||
qCDebug(gpugllogging) << "Strict texture " << texture.source().c_str();
|
||||
object = new GL41StrictResourceTexture(shared_from_this(), texture);
|
||||
break;
|
||||
|
||||
case TextureUsageType::RESOURCE: {
|
||||
qCDebug(gpugllogging) << "variable / Strict texture " << texture.source().c_str();
|
||||
object = new GL41ResourceTexture(shared_from_this(), texture);
|
||||
break;
|
||||
}
|
||||
|
||||
if (object->_samplerStamp <= texture.getSamplerStamp()) {
|
||||
object->syncSampler();
|
||||
}
|
||||
});
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture)
|
||||
: GLTexture(backend, texture, allocate()), _storageStamp { texture.getStamp() }, _size(texture.evalTotalSize()) {
|
||||
using GL41Texture = GL41Backend::GL41Texture;
|
||||
|
||||
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture)
|
||||
: GLTexture(backend, texture, allocate(texture)) {
|
||||
incrementTextureGPUCount();
|
||||
withPreservedTexture([&] {
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat());
|
||||
auto numMips = _gpuObject.getNumMipLevels();
|
||||
for (uint16_t mipLevel = 0; mipLevel < numMips; ++mipLevel) {
|
||||
// Get the mip level dimensions, accounting for the downgrade level
|
||||
Vec3u dimensions = _gpuObject.evalMipDimensions(mipLevel);
|
||||
uint8_t face = 0;
|
||||
for (GLenum target : getFaceTargets(_target)) {
|
||||
const Byte* mipData = nullptr;
|
||||
if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) {
|
||||
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face);
|
||||
mipData = mip->readData();
|
||||
}
|
||||
glTexImage2D(target, mipLevel, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, mipData);
|
||||
(void)CHECK_GL_ERROR();
|
||||
++face;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
GL41Texture::~GL41Texture() {
|
||||
|
||||
GLuint GL41Texture::allocate(const Texture& texture) {
|
||||
GLuint result;
|
||||
glGenTextures(1, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GL41Texture::isOutdated() const {
|
||||
if (_samplerStamp <= _gpuObject.getSamplerStamp()) {
|
||||
return true;
|
||||
}
|
||||
if (TextureUsageType::RESOURCE == _gpuObject.getUsageType() && _contentStamp <= _gpuObject.getDataStamp()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GL41Texture::withPreservedTexture(std::function<void()> f) const {
|
||||
GLint boundTex = -1;
|
||||
switch (_target) {
|
||||
case GL_TEXTURE_2D:
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex);
|
||||
break;
|
||||
|
||||
default:
|
||||
qFatal("Unsupported texture type");
|
||||
}
|
||||
const GLint TRANSFER_TEXTURE_UNIT = 32;
|
||||
glActiveTexture(GL_TEXTURE0 + TRANSFER_TEXTURE_UNIT);
|
||||
glBindTexture(_target, _texture);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
glBindTexture(_target, _texture);
|
||||
f();
|
||||
glBindTexture(_target, boundTex);
|
||||
glBindTexture(_target, 0);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
||||
void GL41Texture::generateMips() const {
|
||||
withPreservedTexture([&] {
|
||||
glGenerateMipmap(_target);
|
||||
|
@ -134,13 +93,35 @@ void GL41Texture::generateMips() const {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GL41Texture::syncContent() const {
|
||||
// FIXME actually copy the texture data
|
||||
_contentStamp = _gpuObject.getDataStamp() + 1;
|
||||
void GL41Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum format, GLenum type, const void* sourcePointer) const {
|
||||
if (GL_TEXTURE_2D == _target) {
|
||||
glTexSubImage2D(_target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
|
||||
} else if (GL_TEXTURE_CUBE_MAP == _target) {
|
||||
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
|
||||
glTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GL41Texture::copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face) const {
|
||||
if (!_gpuObject.isStoredMipFaceAvailable(sourceMip)) {
|
||||
return;
|
||||
}
|
||||
auto size = _gpuObject.evalMipDimensions(sourceMip);
|
||||
auto mipData = _gpuObject.accessStoredMipFace(sourceMip, face);
|
||||
if (mipData) {
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat());
|
||||
copyMipFaceLinesFromTexture(targetMip, face, size, 0, texelFormat.format, texelFormat.type, mipData->readData());
|
||||
} else {
|
||||
qCDebug(gpugllogging) << "Missing mipData level=" << sourceMip << " face=" << (int)face << " for texture " << _gpuObject.source().c_str();
|
||||
}
|
||||
}
|
||||
|
||||
void GL41Texture::syncSampler() const {
|
||||
const Sampler& sampler = _gpuObject.getSampler();
|
||||
|
||||
const auto& fm = FILTER_MODES[sampler.getFilter()];
|
||||
glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, fm.minFilter);
|
||||
glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, fm.magFilter);
|
||||
|
@ -158,12 +139,106 @@ void GL41Texture::syncSampler() const {
|
|||
|
||||
glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
|
||||
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset());
|
||||
|
||||
glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
|
||||
glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
|
||||
|
||||
glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
|
||||
_samplerStamp = _gpuObject.getSamplerStamp() + 1;
|
||||
}
|
||||
|
||||
uint32 GL41Texture::size() const {
|
||||
return _size;
|
||||
using GL41FixedAllocationTexture = GL41Backend::GL41FixedAllocationTexture;
|
||||
|
||||
GL41FixedAllocationTexture::GL41FixedAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL41Texture(backend, texture), _size(texture.evalTotalSize()) {
|
||||
withPreservedTexture([&] {
|
||||
allocateStorage();
|
||||
syncSampler();
|
||||
});
|
||||
}
|
||||
|
||||
GL41FixedAllocationTexture::~GL41FixedAllocationTexture() {
|
||||
}
|
||||
|
||||
void GL41FixedAllocationTexture::allocateStorage() const {
|
||||
const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
|
||||
const auto numMips = _gpuObject.getNumMips();
|
||||
|
||||
// glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y);
|
||||
for (GLint level = 0; level < numMips; level++) {
|
||||
Vec3u dimensions = _gpuObject.evalMipDimensions(level);
|
||||
for (GLenum target : getFaceTargets(_target)) {
|
||||
glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, numMips - 1);
|
||||
}
|
||||
|
||||
void GL41FixedAllocationTexture::syncSampler() const {
|
||||
Parent::syncSampler();
|
||||
const Sampler& sampler = _gpuObject.getSampler();
|
||||
auto baseMip = std::max<uint16_t>(sampler.getMipOffset(), sampler.getMinMip());
|
||||
|
||||
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, baseMip);
|
||||
glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
|
||||
glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.0f : sampler.getMaxMip()));
|
||||
}
|
||||
|
||||
// Renderbuffer attachment textures
|
||||
using GL41AttachmentTexture = GL41Backend::GL41AttachmentTexture;
|
||||
|
||||
GL41AttachmentTexture::GL41AttachmentTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL41FixedAllocationTexture(backend, texture) {
|
||||
Backend::updateTextureGPUFramebufferMemoryUsage(0, size());
|
||||
}
|
||||
|
||||
GL41AttachmentTexture::~GL41AttachmentTexture() {
|
||||
Backend::updateTextureGPUFramebufferMemoryUsage(size(), 0);
|
||||
}
|
||||
|
||||
// Strict resource textures
|
||||
using GL41StrictResourceTexture = GL41Backend::GL41StrictResourceTexture;
|
||||
|
||||
GL41StrictResourceTexture::GL41StrictResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL41FixedAllocationTexture(backend, texture) {
|
||||
withPreservedTexture([&] {
|
||||
|
||||
auto mipLevels = _gpuObject.getNumMips();
|
||||
for (uint16_t sourceMip = 0; sourceMip < mipLevels; sourceMip++) {
|
||||
uint16_t targetMip = sourceMip;
|
||||
size_t maxFace = GLTexture::getFaceCount(_target);
|
||||
for (uint8_t face = 0; face < maxFace; face++) {
|
||||
copyMipFaceFromTexture(sourceMip, targetMip, face);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (texture.isAutogenerateMips()) {
|
||||
generateMips();
|
||||
}
|
||||
}
|
||||
|
||||
// resource textures
|
||||
using GL41ResourceTexture = GL41Backend::GL41ResourceTexture;
|
||||
|
||||
GL41ResourceTexture::GL41ResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL41FixedAllocationTexture(backend, texture) {
|
||||
Backend::updateTextureGPUMemoryUsage(0, size());
|
||||
|
||||
withPreservedTexture([&] {
|
||||
|
||||
auto mipLevels = _gpuObject.getNumMips();
|
||||
for (uint16_t sourceMip = 0; sourceMip < mipLevels; sourceMip++) {
|
||||
uint16_t targetMip = sourceMip;
|
||||
size_t maxFace = GLTexture::getFaceCount(_target);
|
||||
for (uint8_t face = 0; face < maxFace; face++) {
|
||||
copyMipFaceFromTexture(sourceMip, targetMip, face);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (texture.isAutogenerateMips()) {
|
||||
generateMips();
|
||||
}
|
||||
}
|
||||
|
||||
GL41ResourceTexture::~GL41ResourceTexture() {
|
||||
Backend::updateTextureGPUMemoryUsage(size(), 0);
|
||||
}
|
||||
|
|
|
@ -58,10 +58,10 @@ public:
|
|||
~GL45FixedAllocationTexture();
|
||||
|
||||
protected:
|
||||
uint32 size() const override { return _size; }
|
||||
Size size() const override { return _size; }
|
||||
void allocateStorage() const;
|
||||
void syncSampler() const override;
|
||||
const uint32 _size { 0 };
|
||||
const Size _size { 0 };
|
||||
};
|
||||
|
||||
class GL45AttachmentTexture : public GL45FixedAllocationTexture {
|
||||
|
@ -173,7 +173,7 @@ public:
|
|||
bool canDemote() const { return _allocatedMip < _maxAllocatedMip; }
|
||||
bool hasPendingTransfers() const { return _populatedMip > _allocatedMip; }
|
||||
void executeNextTransfer(const TexturePointer& currentTexture);
|
||||
uint32 size() const override { return _size; }
|
||||
Size size() const override { return _size; }
|
||||
virtual void populateTransferQueue() = 0;
|
||||
virtual void promote() = 0;
|
||||
virtual void demote() = 0;
|
||||
|
@ -188,7 +188,7 @@ public:
|
|||
// The highest (lowest resolution) mip that we will support, relative to the number
|
||||
// of mips in the gpu::Texture object
|
||||
uint16 _maxAllocatedMip { 0 };
|
||||
uint32 _size { 0 };
|
||||
Size _size { 0 };
|
||||
// Contains a series of lambdas that when executed will transfer data to the GPU, modify
|
||||
// the _populatedMip and update the sampler in order to fully populate the allocated texture
|
||||
// until _populatedMip == _allocatedMip
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <glm/gtx/component_wise.hpp>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include "../gl/GLTexelFormat.h"
|
||||
|
@ -167,8 +166,10 @@ void GL45Texture::syncSampler() const {
|
|||
glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]);
|
||||
glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]);
|
||||
glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]);
|
||||
|
||||
glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
|
||||
glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
|
||||
|
||||
glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip());
|
||||
glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
|
||||
}
|
||||
|
@ -186,10 +187,12 @@ GL45FixedAllocationTexture::~GL45FixedAllocationTexture() {
|
|||
void GL45FixedAllocationTexture::allocateStorage() const {
|
||||
const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
|
||||
const auto dimensions = _gpuObject.getDimensions();
|
||||
const auto mips = _gpuObject.getNumMipLevels();
|
||||
const auto mips = _gpuObject.getNumMips();
|
||||
|
||||
glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y);
|
||||
|
||||
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, mips - 1);
|
||||
}
|
||||
|
||||
void GL45FixedAllocationTexture::syncSampler() const {
|
||||
|
@ -216,7 +219,7 @@ GL45AttachmentTexture::~GL45AttachmentTexture() {
|
|||
using GL45StrictResourceTexture = GL45Backend::GL45StrictResourceTexture;
|
||||
|
||||
GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45FixedAllocationTexture(backend, texture) {
|
||||
auto mipLevels = _gpuObject.getNumMipLevels();
|
||||
auto mipLevels = _gpuObject.getNumMips();
|
||||
for (uint16_t sourceMip = 0; sourceMip < mipLevels; ++sourceMip) {
|
||||
uint16_t targetMip = sourceMip;
|
||||
size_t maxFace = GLTexture::getFaceCount(_target);
|
||||
|
|
|
@ -441,7 +441,7 @@ void GL45VariableAllocationTexture::executeNextTransfer(const TexturePointer& cu
|
|||
using GL45ResourceTexture = GL45Backend::GL45ResourceTexture;
|
||||
|
||||
GL45ResourceTexture::GL45ResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45VariableAllocationTexture(backend, texture) {
|
||||
auto mipLevels = texture.evalNumMips();
|
||||
auto mipLevels = texture.getNumMips();
|
||||
_allocatedMip = mipLevels;
|
||||
uvec3 mipDimensions;
|
||||
for (uint16_t mip = 0; mip < mipLevels; ++mip) {
|
||||
|
@ -463,10 +463,10 @@ void GL45ResourceTexture::allocateStorage(uint16 allocatedMip) {
|
|||
_allocatedMip = allocatedMip;
|
||||
const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
|
||||
const auto dimensions = _gpuObject.evalMipDimensions(_allocatedMip);
|
||||
const auto totalMips = _gpuObject.getNumMipLevels();
|
||||
const auto totalMips = _gpuObject.getNumMips();
|
||||
const auto mips = totalMips - _allocatedMip;
|
||||
glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y);
|
||||
auto mipLevels = _gpuObject.getNumMipLevels();
|
||||
auto mipLevels = _gpuObject.getNumMips();
|
||||
_size = 0;
|
||||
for (uint16_t mip = _allocatedMip; mip < mipLevels; ++mip) {
|
||||
_size += _gpuObject.evalMipSize(mip);
|
||||
|
@ -476,7 +476,7 @@ void GL45ResourceTexture::allocateStorage(uint16 allocatedMip) {
|
|||
}
|
||||
|
||||
void GL45ResourceTexture::copyMipsFromTexture() {
|
||||
auto mipLevels = _gpuObject.getNumMipLevels();
|
||||
auto mipLevels = _gpuObject.getNumMips();
|
||||
size_t maxFace = GLTexture::getFaceCount(_target);
|
||||
for (uint16_t sourceMip = _populatedMip; sourceMip < mipLevels; ++sourceMip) {
|
||||
uint16_t targetMip = sourceMip - _allocatedMip;
|
||||
|
@ -495,13 +495,13 @@ void GL45ResourceTexture::promote() {
|
|||
PROFILE_RANGE(render_gpu_gl, __FUNCTION__);
|
||||
Q_ASSERT(_allocatedMip > 0);
|
||||
GLuint oldId = _id;
|
||||
uint32_t oldSize = _size;
|
||||
auto oldSize = _size;
|
||||
// create new texture
|
||||
const_cast<GLuint&>(_id) = allocate(_gpuObject);
|
||||
uint16_t oldAllocatedMip = _allocatedMip;
|
||||
// allocate storage for new level
|
||||
allocateStorage(_allocatedMip - std::min<uint16_t>(_allocatedMip, 2));
|
||||
uint16_t mips = _gpuObject.getNumMipLevels();
|
||||
uint16_t mips = _gpuObject.getNumMips();
|
||||
// copy pre-existing mips
|
||||
for (uint16_t mip = _populatedMip; mip < mips; ++mip) {
|
||||
auto mipDimensions = _gpuObject.evalMipDimensions(mip);
|
||||
|
@ -534,7 +534,7 @@ void GL45ResourceTexture::demote() {
|
|||
const_cast<GLuint&>(_id) = allocate(_gpuObject);
|
||||
allocateStorage(_allocatedMip + 1);
|
||||
_populatedMip = std::max(_populatedMip, _allocatedMip);
|
||||
uint16_t mips = _gpuObject.getNumMipLevels();
|
||||
uint16_t mips = _gpuObject.getNumMips();
|
||||
// copy pre-existing mips
|
||||
for (uint16_t mip = _populatedMip; mip < mips; ++mip) {
|
||||
auto mipDimensions = _gpuObject.evalMipDimensions(mip);
|
||||
|
|
|
@ -265,7 +265,7 @@ void Context::incrementBufferGPUCount() {
|
|||
auto total = ++_bufferGPUCount;
|
||||
if (total > max.load()) {
|
||||
max = total;
|
||||
qCDebug(gpulogging) << "New max GPU buffers " << total;
|
||||
// qCDebug(gpulogging) << "New max GPU buffers " << total;
|
||||
}
|
||||
}
|
||||
void Context::decrementBufferGPUCount() {
|
||||
|
@ -299,7 +299,7 @@ void Context::incrementTextureGPUCount() {
|
|||
auto total = ++_textureGPUCount;
|
||||
if (total > max.load()) {
|
||||
max = total;
|
||||
qCDebug(gpulogging) << "New max GPU textures " << total;
|
||||
// qCDebug(gpulogging) << "New max GPU textures " << total;
|
||||
}
|
||||
}
|
||||
void Context::decrementTextureGPUCount() {
|
||||
|
@ -311,7 +311,7 @@ void Context::incrementTextureGPUSparseCount() {
|
|||
auto total = ++_textureGPUSparseCount;
|
||||
if (total > max.load()) {
|
||||
max = total;
|
||||
qCDebug(gpulogging) << "New max GPU textures " << total;
|
||||
// qCDebug(gpulogging) << "New max GPU textures " << total;
|
||||
}
|
||||
}
|
||||
void Context::decrementTextureGPUSparseCount() {
|
||||
|
@ -378,7 +378,7 @@ void Context::incrementTextureGPUTransferCount() {
|
|||
auto total = ++_textureGPUTransferCount;
|
||||
if (total > max.load()) {
|
||||
max = total;
|
||||
qCDebug(gpulogging) << "New max GPU textures transfers" << total;
|
||||
// qCDebug(gpulogging) << "New max GPU textures transfers" << total;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ Framebuffer* Framebuffer::create(const std::string& name) {
|
|||
Framebuffer* Framebuffer::create(const std::string& name, const Format& colorBufferFormat, uint16 width, uint16 height) {
|
||||
auto framebuffer = Framebuffer::create(name);
|
||||
|
||||
auto colorTexture = TexturePointer(Texture::createRenderBuffer(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
|
||||
auto colorTexture = TexturePointer(Texture::createRenderBuffer(colorBufferFormat, width, height, Texture::SINGLE_MIP, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
|
||||
colorTexture->setSource("Framebuffer::colorTexture");
|
||||
|
||||
framebuffer->setRenderBuffer(0, colorTexture);
|
||||
|
@ -43,8 +43,8 @@ Framebuffer* Framebuffer::create(const std::string& name, const Format& colorBuf
|
|||
Framebuffer* Framebuffer::create(const std::string& name, const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height) {
|
||||
auto framebuffer = Framebuffer::create(name);
|
||||
|
||||
auto colorTexture = TexturePointer(Texture::createRenderBuffer(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
|
||||
auto depthTexture = TexturePointer(Texture::createRenderBuffer(depthStencilBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
|
||||
auto colorTexture = TexturePointer(Texture::createRenderBuffer(colorBufferFormat, width, height, Texture::SINGLE_MIP, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
|
||||
auto depthTexture = TexturePointer(Texture::createRenderBuffer(depthStencilBufferFormat, width, height, Texture::SINGLE_MIP, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
|
||||
framebuffer->setRenderBuffer(0, colorTexture);
|
||||
framebuffer->setDepthStencilBuffer(depthTexture, depthStencilBufferFormat);
|
||||
|
||||
|
|
|
@ -149,8 +149,14 @@ PixelsPointer MemoryStorage::getMipFace(uint16 level, uint8 face) const {
|
|||
return PixelsPointer();
|
||||
}
|
||||
|
||||
|
||||
Size MemoryStorage::getMipFaceSize(uint16 level, uint8 face) const {
|
||||
return getMipFace(level, face)->getSize();
|
||||
PixelsPointer mipFace = getMipFace(level, face);
|
||||
if (mipFace) {
|
||||
return mipFace->getSize();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool MemoryStorage::isMipAvailable(uint16 level, uint8 face) const {
|
||||
|
@ -209,44 +215,43 @@ void Texture::MemoryStorage::assignMipFaceData(uint16 level, uint8 face, const s
|
|||
Texture* Texture::createExternal(const ExternalRecycler& recycler, const Sampler& sampler) {
|
||||
Texture* tex = new Texture(TextureUsageType::EXTERNAL);
|
||||
tex->_type = TEX_2D;
|
||||
tex->_maxMip = 0;
|
||||
tex->_maxMipLevel = 0;
|
||||
tex->_sampler = sampler;
|
||||
tex->setExternalRecycler(recycler);
|
||||
return tex;
|
||||
}
|
||||
|
||||
Texture* Texture::createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) {
|
||||
return create(TextureUsageType::RENDERBUFFER, TEX_2D, texelFormat, width, height, 1, 1, 0, sampler);
|
||||
Texture* Texture::createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips, const Sampler& sampler) {
|
||||
return create(TextureUsageType::RENDERBUFFER, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler);
|
||||
}
|
||||
|
||||
Texture* Texture::create1D(const Element& texelFormat, uint16 width, const Sampler& sampler) {
|
||||
return create(TextureUsageType::RESOURCE, TEX_1D, texelFormat, width, 1, 1, 1, 0, sampler);
|
||||
Texture* Texture::create1D(const Element& texelFormat, uint16 width, uint16 numMips, const Sampler& sampler) {
|
||||
return create(TextureUsageType::RESOURCE, TEX_1D, texelFormat, width, 1, 1, 1, 0, numMips, sampler);
|
||||
}
|
||||
|
||||
Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) {
|
||||
return create(TextureUsageType::RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, sampler);
|
||||
Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips, const Sampler& sampler) {
|
||||
return create(TextureUsageType::RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler);
|
||||
}
|
||||
|
||||
Texture* Texture::createStrict(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) {
|
||||
return create(TextureUsageType::STRICT_RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, sampler);
|
||||
Texture* Texture::createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips, const Sampler& sampler) {
|
||||
return create(TextureUsageType::STRICT_RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler);
|
||||
}
|
||||
|
||||
Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler) {
|
||||
return create(TextureUsageType::RESOURCE, TEX_3D, texelFormat, width, height, depth, 1, 0, sampler);
|
||||
Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numMips, const Sampler& sampler) {
|
||||
return create(TextureUsageType::RESOURCE, TEX_3D, texelFormat, width, height, depth, 1, 0, numMips, sampler);
|
||||
}
|
||||
|
||||
Texture* Texture::createCube(const Element& texelFormat, uint16 width, const Sampler& sampler) {
|
||||
return create(TextureUsageType::RESOURCE, TEX_CUBE, texelFormat, width, width, 1, 1, 0, sampler);
|
||||
Texture* Texture::createCube(const Element& texelFormat, uint16 width, uint16 numMips, const Sampler& sampler) {
|
||||
return create(TextureUsageType::RESOURCE, TEX_CUBE, texelFormat, width, width, 1, 1, 0, numMips, sampler);
|
||||
}
|
||||
|
||||
Texture* Texture::create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler)
|
||||
Texture* Texture::create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips, const Sampler& sampler)
|
||||
{
|
||||
Texture* tex = new Texture(usageType);
|
||||
tex->_storage.reset(new MemoryStorage());
|
||||
tex->_type = type;
|
||||
tex->_storage->assignTexture(tex);
|
||||
tex->_maxMip = 0;
|
||||
tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices);
|
||||
tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices, numMips);
|
||||
|
||||
tex->_sampler = sampler;
|
||||
|
||||
|
@ -278,7 +283,7 @@ Texture::~Texture() {
|
|||
}
|
||||
}
|
||||
|
||||
Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) {
|
||||
Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips) {
|
||||
if (width && height && depth && numSamples) {
|
||||
bool changed = false;
|
||||
|
||||
|
@ -313,9 +318,19 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt
|
|||
_depth = depth;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
||||
if ((_maxMipLevel + 1) != numMips) {
|
||||
_maxMipLevel = safeNumMips(numMips) - 1;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (texelFormat != _texelFormat) {
|
||||
_texelFormat = texelFormat;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Evaluate the new size with the new format
|
||||
uint32_t size = NUM_FACES_PER_TYPE[_type] *_width * _height * _depth * _numSamples * texelFormat.getSize();
|
||||
Size size = NUM_FACES_PER_TYPE[_type] * _height * _depth * evalPaddedSize(_numSamples * _width * _texelFormat.getSize());
|
||||
|
||||
// If size change then we need to reset
|
||||
if (changed || (size != getSize())) {
|
||||
|
@ -324,12 +339,6 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt
|
|||
_stamp++;
|
||||
}
|
||||
|
||||
// TexelFormat might have change, but it's mostly interpretation
|
||||
if (texelFormat != _texelFormat) {
|
||||
_texelFormat = texelFormat;
|
||||
_stamp++;
|
||||
}
|
||||
|
||||
// Here the Texture has been fully defined from the gpu point of view (size and format)
|
||||
_defined = true;
|
||||
} else {
|
||||
|
@ -339,23 +348,6 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt
|
|||
return _size;
|
||||
}
|
||||
|
||||
Texture::Size Texture::resize1D(uint16 width, uint16 numSamples) {
|
||||
return resize(TEX_1D, getTexelFormat(), width, 1, 1, numSamples, 0);
|
||||
}
|
||||
Texture::Size Texture::resize2D(uint16 width, uint16 height, uint16 numSamples) {
|
||||
return resize(TEX_2D, getTexelFormat(), width, height, 1, numSamples, 0);
|
||||
}
|
||||
Texture::Size Texture::resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples) {
|
||||
return resize(TEX_3D, getTexelFormat(), width, height, depth, numSamples, 0);
|
||||
}
|
||||
Texture::Size Texture::resizeCube(uint16 width, uint16 numSamples) {
|
||||
return resize(TEX_CUBE, getTexelFormat(), width, 1, 1, numSamples, 0);
|
||||
}
|
||||
|
||||
Texture::Size Texture::reformat(const Element& texelFormat) {
|
||||
return resize(_type, texelFormat, getWidth(), getHeight(), getDepth(), getNumSamples(), _numSlices);
|
||||
}
|
||||
|
||||
bool Texture::isColorRenderTarget() const {
|
||||
return (_texelFormat.getSemantic() == gpu::RGBA);
|
||||
}
|
||||
|
@ -364,7 +356,7 @@ bool Texture::isDepthStencilRenderTarget() const {
|
|||
return (_texelFormat.getSemantic() == gpu::DEPTH) || (_texelFormat.getSemantic() == gpu::DEPTH_STENCIL);
|
||||
}
|
||||
|
||||
uint16 Texture::evalDimNumMips(uint16 size) {
|
||||
uint16 Texture::evalDimMaxNumMips(uint16 size) {
|
||||
double largerDim = size;
|
||||
double val = log(largerDim)/log(2.0);
|
||||
return 1 + (uint16) val;
|
||||
|
@ -372,7 +364,7 @@ uint16 Texture::evalDimNumMips(uint16 size) {
|
|||
|
||||
static const double LOG_2 = log(2.0);
|
||||
|
||||
uint16 Texture::evalNumMips(const Vec3u& dimensions) {
|
||||
uint16 Texture::evalMaxNumMips(const Vec3u& dimensions) {
|
||||
double largerDim = glm::compMax(dimensions);
|
||||
double val = log(largerDim) / LOG_2;
|
||||
return 1 + (uint16)val;
|
||||
|
@ -380,8 +372,34 @@ uint16 Texture::evalNumMips(const Vec3u& dimensions) {
|
|||
|
||||
// The number mips that the texture could have if all existed
|
||||
// = log2(max(width, height, depth))
|
||||
uint16 Texture::evalNumMips() const {
|
||||
return evalNumMips({ _width, _height, _depth });
|
||||
uint16 Texture::evalMaxNumMips() const {
|
||||
return evalMaxNumMips({ _width, _height, _depth });
|
||||
}
|
||||
|
||||
// Check a num of mips requested against the maximum possible specified
|
||||
// if passing -1 then answer the max
|
||||
// simply does (askedNumMips == 0 ? maxNumMips : (numstd::min(askedNumMips, maxNumMips))
|
||||
uint16 Texture::safeNumMips(uint16 askedNumMips, uint16 maxNumMips) {
|
||||
if (askedNumMips > 0) {
|
||||
return std::min(askedNumMips, maxNumMips);
|
||||
} else {
|
||||
return maxNumMips;
|
||||
}
|
||||
}
|
||||
|
||||
// Same but applied to this texture's num max mips from evalNumMips()
|
||||
uint16 Texture::safeNumMips(uint16 askedNumMips) const {
|
||||
return safeNumMips(askedNumMips, evalMaxNumMips());
|
||||
}
|
||||
|
||||
Size Texture::evalTotalSize(uint16 startingMip) const {
|
||||
Size size = 0;
|
||||
uint16 minMipLevel = std::max(getMinMip(), startingMip);
|
||||
uint16 maxMipLevel = getMaxMip();
|
||||
for (uint16 level = minMipLevel; level <= maxMipLevel; level++) {
|
||||
size += evalMipSize(level);
|
||||
}
|
||||
return size * getNumSlices();
|
||||
}
|
||||
|
||||
void Texture::setStoredMipFormat(const Element& format) {
|
||||
|
@ -408,7 +426,7 @@ void Texture::assignStoredMip(uint16 level, storage::StoragePointer& storage) {
|
|||
if (_autoGenerateMips) {
|
||||
return;
|
||||
}
|
||||
if (level >= evalNumMips()) {
|
||||
if (level >= getNumMips()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -418,7 +436,6 @@ void Texture::assignStoredMip(uint16 level, storage::StoragePointer& storage) {
|
|||
auto size = storage->size();
|
||||
if (storage->size() == expectedSize) {
|
||||
_storage->assignMipData(level, storage);
|
||||
_maxMip = std::max(_maxMip, level);
|
||||
_stamp++;
|
||||
} else if (size > expectedSize) {
|
||||
// NOTE: We are facing this case sometime because apparently QImage (from where we get the bits) is generating images
|
||||
|
@ -426,7 +443,6 @@ void Texture::assignStoredMip(uint16 level, storage::StoragePointer& storage) {
|
|||
// We should probably consider something a bit more smart to get the correct result but for now (UI elements)
|
||||
// it seems to work...
|
||||
_storage->assignMipData(level, storage);
|
||||
_maxMip = std::max(_maxMip, level);
|
||||
_stamp++;
|
||||
}
|
||||
}
|
||||
|
@ -437,7 +453,7 @@ void Texture::assignStoredMipFace(uint16 level, uint8 face, storage::StoragePoin
|
|||
if (_autoGenerateMips) {
|
||||
return;
|
||||
}
|
||||
if (level >= evalNumMips()) {
|
||||
if (level >= getNumMips()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -447,7 +463,6 @@ void Texture::assignStoredMipFace(uint16 level, uint8 face, storage::StoragePoin
|
|||
auto size = storage->size();
|
||||
if (size == expectedSize) {
|
||||
_storage->assignMipFaceData(level, face, storage);
|
||||
_maxMip = std::max(_maxMip, level);
|
||||
_stamp++;
|
||||
} else if (size > expectedSize) {
|
||||
// NOTE: We are facing this case sometime because apparently QImage (from where we get the bits) is generating images
|
||||
|
@ -455,71 +470,36 @@ void Texture::assignStoredMipFace(uint16 level, uint8 face, storage::StoragePoin
|
|||
// We should probably consider something a bit more smart to get the correct result but for now (UI elements)
|
||||
// it seems to work...
|
||||
_storage->assignMipFaceData(level, face, storage);
|
||||
_maxMip = std::max(_maxMip, level);
|
||||
_stamp++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint16 Texture::autoGenerateMips(uint16 maxMip) {
|
||||
void Texture::setAutoGenerateMips(bool enable) {
|
||||
bool changed = false;
|
||||
if (!_autoGenerateMips) {
|
||||
changed = true;
|
||||
_autoGenerateMips = true;
|
||||
}
|
||||
|
||||
auto newMaxMip = std::min((uint16)(evalNumMips() - 1), maxMip);
|
||||
if (newMaxMip != _maxMip) {
|
||||
changed = true;
|
||||
_maxMip = newMaxMip;;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
_stamp++;
|
||||
}
|
||||
|
||||
return _maxMip;
|
||||
}
|
||||
|
||||
uint16 Texture::getStoredMipWidth(uint16 level) const {
|
||||
if (!isStoredMipFaceAvailable(level)) {
|
||||
return 0;
|
||||
Size Texture::getStoredMipSize(uint16 level) const {
|
||||
PixelsPointer mipFace = accessStoredMipFace(level);
|
||||
Size size = 0;
|
||||
if (mipFace && mipFace->getSize()) {
|
||||
for (int face = 0; face < getNumFaces(); face++) {
|
||||
size += getStoredMipFaceSize(level, face);
|
||||
}
|
||||
}
|
||||
return evalMipWidth(level);
|
||||
return size;
|
||||
}
|
||||
|
||||
uint16 Texture::getStoredMipHeight(uint16 level) const {
|
||||
if (!isStoredMipFaceAvailable(level)) {
|
||||
return 0;
|
||||
}
|
||||
return evalMipHeight(level);
|
||||
}
|
||||
|
||||
uint16 Texture::getStoredMipDepth(uint16 level) const {
|
||||
if (!isStoredMipFaceAvailable(level)) {
|
||||
return 0;
|
||||
}
|
||||
return evalMipDepth(level);
|
||||
}
|
||||
|
||||
uint32 Texture::getStoredMipNumTexels(uint16 level) const {
|
||||
if (!isStoredMipFaceAvailable(level)) {
|
||||
return 0;
|
||||
}
|
||||
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level);
|
||||
}
|
||||
|
||||
uint32 Texture::getStoredMipSize(uint16 level) const {
|
||||
if (!isStoredMipFaceAvailable(level)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize();
|
||||
}
|
||||
|
||||
gpu::Resource::Size Texture::getStoredSize() const {
|
||||
auto size = 0;
|
||||
for (int level = 0; level < evalNumMips(); ++level) {
|
||||
Size Texture::getStoredSize() const {
|
||||
Size size = 0;
|
||||
for (int level = 0; level < getNumMips(); level++) {
|
||||
size += getStoredMipSize(level);
|
||||
}
|
||||
return size;
|
||||
|
@ -937,7 +917,7 @@ bool TextureSource::isDefined() const {
|
|||
|
||||
bool Texture::setMinMip(uint16 newMinMip) {
|
||||
uint16 oldMinMip = _minMip;
|
||||
_minMip = std::min(std::max(_minMip, newMinMip), _maxMip);
|
||||
_minMip = std::min(std::max(_minMip, newMinMip), getMaxMip());
|
||||
return oldMinMip != _minMip;
|
||||
}
|
||||
|
||||
|
|
|
@ -232,9 +232,7 @@ public:
|
|||
bool operator!=(const Usage& usage) { return (_flags != usage._flags); }
|
||||
};
|
||||
|
||||
using PixelsPointer = storage::StoragePointer;
|
||||
|
||||
enum Type {
|
||||
enum Type : uint8 {
|
||||
TEX_1D = 0,
|
||||
TEX_2D,
|
||||
TEX_3D,
|
||||
|
@ -255,7 +253,13 @@ public:
|
|||
NUM_CUBE_FACES, // Not a valid vace index
|
||||
};
|
||||
|
||||
// Lines of pixels are padded to be a multiple of "PACKING_SIZE" which is 4 bytes
|
||||
static const uint32 PACKING_SIZE = 4;
|
||||
static uint8 evalPaddingNumBytes(Size byteSize) { return (uint8) (3 - (byteSize + 3) % PACKING_SIZE); }
|
||||
static Size evalPaddedSize(Size byteSize) { return byteSize + (Size) evalPaddingNumBytes(byteSize); }
|
||||
|
||||
|
||||
using PixelsPointer = storage::StoragePointer;
|
||||
class Storage {
|
||||
public:
|
||||
Storage() {}
|
||||
|
@ -322,14 +326,19 @@ public:
|
|||
friend class Texture;
|
||||
};
|
||||
|
||||
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* createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler = Sampler());
|
||||
static Texture* createStrict(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler = Sampler());
|
||||
static const uint16 MAX_NUM_MIPS = 0;
|
||||
static const uint16 SINGLE_MIP = 1;
|
||||
static Texture* create1D(const Element& texelFormat, uint16 width, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
|
||||
static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
|
||||
static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
|
||||
static Texture* createCube(const Element& texelFormat, uint16 width, uint16 numMips = 1, const Sampler& sampler = Sampler());
|
||||
static Texture* createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
|
||||
static Texture* createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
|
||||
static Texture* createExternal(const ExternalRecycler& recycler, const Sampler& sampler = Sampler());
|
||||
|
||||
// After the texture has been created, it should be defined
|
||||
bool isDefined() const { return _defined; }
|
||||
|
||||
Texture(TextureUsageType usageType);
|
||||
Texture(const Texture& buf); // deep copy of the sysmem texture
|
||||
Texture& operator=(const Texture& buf); // deep copy of the sysmem texture
|
||||
|
@ -339,20 +348,9 @@ public:
|
|||
Stamp getDataStamp() const { return _storage->getStamp(); }
|
||||
|
||||
// The theoretical size in bytes of data stored in the texture
|
||||
// For the master (level) first level of mip
|
||||
Size getSize() const override { return _size; }
|
||||
|
||||
// The actual size in bytes of data stored in the texture
|
||||
Size getStoredSize() const;
|
||||
|
||||
// Resize, unless auto mips mode would destroy all the sub mips
|
||||
Size resize1D(uint16 width, uint16 numSamples);
|
||||
Size resize2D(uint16 width, uint16 height, uint16 numSamples);
|
||||
Size resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples);
|
||||
Size resizeCube(uint16 width, uint16 numSamples);
|
||||
|
||||
// Reformat, unless auto mips mode would destroy all the sub mips
|
||||
Size reformat(const Element& texelFormat);
|
||||
|
||||
// Size and format
|
||||
Type getType() const { return _type; }
|
||||
TextureUsageType getUsageType() const { return _usageType; }
|
||||
|
@ -361,23 +359,18 @@ public:
|
|||
bool isDepthStencilRenderTarget() const;
|
||||
|
||||
const Element& getTexelFormat() const { return _texelFormat; }
|
||||
bool hasBorder() const { return false; }
|
||||
|
||||
Vec3u getDimensions() const { return Vec3u(_width, _height, _depth); }
|
||||
uint16 getWidth() const { return _width; }
|
||||
uint16 getHeight() const { return _height; }
|
||||
uint16 getDepth() const { return _depth; }
|
||||
|
||||
uint32 getRowPitch() const { return getWidth() * getTexelFormat().getSize(); }
|
||||
|
||||
// The number of faces is mostly used for cube map, and maybe for stereo ? otherwise it's 1
|
||||
// For cube maps, this means the pixels of the different faces are supposed to be packed back to back in a mip
|
||||
// as if the height was NUM_FACES time bigger.
|
||||
static uint8 NUM_FACES_PER_TYPE[NUM_TYPES];
|
||||
uint8 getNumFaces() const { return NUM_FACES_PER_TYPE[getType()]; }
|
||||
|
||||
uint32 getNumTexels() const { return _width * _height * _depth * getNumFaces(); }
|
||||
|
||||
// The texture is an array if the _numSlices is not 0.
|
||||
// otherwise, if _numSLices is 0, then the texture is NOT an array
|
||||
// The number of slices returned is 1 at the minimum (if not an array) or the actual _numSlices.
|
||||
|
@ -385,79 +378,74 @@ public:
|
|||
uint16 getNumSlices() const { return (isArray() ? _numSlices : 1); }
|
||||
|
||||
uint16 getNumSamples() const { return _numSamples; }
|
||||
|
||||
|
||||
// NumSamples can only have certain values based on the hw
|
||||
static uint16 evalNumSamplesUsed(uint16 numSamplesTried);
|
||||
|
||||
// max mip is in the range [ 0 if no sub mips, log2(max(width, height, depth))]
|
||||
// It is defined at creation time (immutable)
|
||||
uint16 getMaxMip() const { return _maxMipLevel; }
|
||||
uint16 getNumMips() const { return _maxMipLevel + 1; }
|
||||
|
||||
// Mips size evaluation
|
||||
|
||||
// The number mips that a dimension could haves
|
||||
// = 1 + log2(size)
|
||||
static uint16 evalDimNumMips(uint16 size);
|
||||
static uint16 evalDimMaxNumMips(uint16 size);
|
||||
|
||||
// The number mips that the texture could have if all existed
|
||||
// = 1 + log2(max(width, height, depth))
|
||||
uint16 evalNumMips() const;
|
||||
uint16 evalMaxNumMips() const;
|
||||
static uint16 evalMaxNumMips(const Vec3u& dimensions);
|
||||
|
||||
static uint16 evalNumMips(const Vec3u& dimensions);
|
||||
// Check a num of mips requested against the maximum possible specified
|
||||
// if passing -1 then answer the max
|
||||
// simply does (askedNumMips == -1 ? maxMips : (numstd::min(askedNumMips, max))
|
||||
static uint16 safeNumMips(uint16 askedNumMips, uint16 maxMips);
|
||||
|
||||
// Same but applied to this texture's num max mips from evalNumMips()
|
||||
uint16 safeNumMips(uint16 askedNumMips) const;
|
||||
|
||||
// Eval the size that the mips level SHOULD have
|
||||
// not the one stored in the Texture
|
||||
static const uint MIN_DIMENSION = 1;
|
||||
|
||||
Vec3u evalMipDimensions(uint16 level) const;
|
||||
uint16 evalMipWidth(uint16 level) const { return std::max(_width >> level, 1); }
|
||||
uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); }
|
||||
uint16 evalMipDepth(uint16 level) const { return std::max(_depth >> level, 1); }
|
||||
|
||||
// The size of a face is a multiple of the padded line = (width * texelFormat_size + alignment padding)
|
||||
Size evalMipLineSize(uint16 level) const { return evalPaddedSize(evalMipWidth(level) * getTexelFormat().getSize()); }
|
||||
|
||||
// Size for each face of a mip at a particular level
|
||||
uint32 evalMipFaceNumTexels(uint16 level) const { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); }
|
||||
uint32 evalMipFaceSize(uint16 level) const { return evalMipFaceNumTexels(level) * getTexelFormat().getSize(); }
|
||||
Size evalMipFaceSize(uint16 level) const { return evalMipLineSize(level) * evalMipHeight(level) * evalMipDepth(level); }
|
||||
|
||||
// Total size for the mip
|
||||
uint32 evalMipNumTexels(uint16 level) const { return evalMipFaceNumTexels(level) * getNumFaces(); }
|
||||
uint32 evalMipSize(uint16 level) const { return evalMipNumTexels(level) * getTexelFormat().getSize(); }
|
||||
Size evalMipSize(uint16 level) const { return evalMipFaceSize(level) * getNumFaces(); }
|
||||
|
||||
uint32 evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); }
|
||||
uint32 evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); }
|
||||
// Total size for all the mips of the texture
|
||||
Size evalTotalSize(uint16 startingMip = 0) const;
|
||||
|
||||
uint32 evalTotalSize(uint16 startingMip = 0) const {
|
||||
uint32 size = 0;
|
||||
uint16 minMipLevel = std::max(getMinMip(), startingMip);
|
||||
uint16 maxMipLevel = getMaxMip();
|
||||
for (uint16 l = minMipLevel; l <= maxMipLevel; l++) {
|
||||
size += evalMipSize(l);
|
||||
}
|
||||
return size * getNumSlices();
|
||||
}
|
||||
|
||||
// max mip is in the range [ 0 if no sub mips, log2(max(width, height, depth))]
|
||||
// if autoGenerateMip is on => will provide the maxMIp level specified
|
||||
// else provide the deepest mip level provided through assignMip
|
||||
uint16 getMaxMip() const { return _maxMip; }
|
||||
uint16 getMinMip() const { return _minMip; }
|
||||
uint16 getNumMipLevels() const { return _maxMip + 1; }
|
||||
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
|
||||
// Compute the theorical size of the texture elements storage depending on the specified format
|
||||
Size evalStoredMipLineSize(uint16 level, const Element& format) const { return evalPaddedSize(evalMipWidth(level) * format.getSize()); }
|
||||
Size evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); }
|
||||
Size evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); }
|
||||
|
||||
// For convenience assign a source name
|
||||
const std::string& source() const { return _source; }
|
||||
void setSource(const std::string& source) { _source = source; }
|
||||
|
||||
// Potentially change the minimum mip (mostly for debugging purpose)
|
||||
bool setMinMip(uint16 newMinMip);
|
||||
bool incremementMinMip(uint16 count = 1);
|
||||
uint16 getMinMip() const { return _minMip; }
|
||||
uint16 usedMipLevels() const { return (getNumMips() - _minMip); }
|
||||
|
||||
// Generate the mips automatically
|
||||
// But the sysmem version is not available
|
||||
// Generate the sub mips automatically for the texture
|
||||
// If the storage version is not available (from CPU memory)
|
||||
// Only works for the standard formats
|
||||
// Specify the maximum Mip level available
|
||||
// 0 is the default one
|
||||
// 1 is the first level
|
||||
// ...
|
||||
// nbMips - 1 is the last mip level
|
||||
//
|
||||
// If -1 then all the mips are generated
|
||||
//
|
||||
// Return the totalnumber of mips that will be available
|
||||
uint16 autoGenerateMips(uint16 maxMip);
|
||||
void setAutoGenerateMips(bool enable);
|
||||
bool isAutogenerateMips() const { return _autoGenerateMips; }
|
||||
|
||||
// Managing Storage and mips
|
||||
|
@ -471,30 +459,22 @@ public:
|
|||
// in case autoGen is on, this doesn't allocate
|
||||
// Explicitely assign mip data for a certain level
|
||||
// If Bytes is NULL then simply allocate the space so mip sysmem can be accessed
|
||||
|
||||
void assignStoredMip(uint16 level, Size size, const Byte* bytes);
|
||||
void assignStoredMipFace(uint16 level, uint8 face, Size size, const Byte* bytes);
|
||||
|
||||
void assignStoredMip(uint16 level, storage::StoragePointer& storage);
|
||||
void assignStoredMipFace(uint16 level, uint8 face, storage::StoragePointer& storage);
|
||||
|
||||
// Access the the sub mips
|
||||
bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); }
|
||||
// Access the stored mips and faces
|
||||
const PixelsPointer accessStoredMipFace(uint16 level, uint8 face = 0) const { return _storage->getMipFace(level, face); }
|
||||
bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); }
|
||||
Size getStoredMipFaceSize(uint16 level, uint8 face = 0) const { return _storage->getMipFaceSize(level, face); }
|
||||
Size getStoredMipSize(uint16 level) const;
|
||||
Size getStoredSize() const;
|
||||
|
||||
void setStorage(std::unique_ptr<Storage>& newStorage);
|
||||
void setKtxBacking(const std::string& filename);
|
||||
|
||||
// access sizes for the stored mips
|
||||
uint16 getStoredMipWidth(uint16 level) const;
|
||||
uint16 getStoredMipHeight(uint16 level) const;
|
||||
uint16 getStoredMipDepth(uint16 level) const;
|
||||
uint32 getStoredMipNumTexels(uint16 level) const;
|
||||
uint32 getStoredMipSize(uint16 level) const;
|
||||
|
||||
bool isDefined() const { return _defined; }
|
||||
|
||||
// Usage is a a set of flags providing Semantic about the usage of the Texture.
|
||||
void setUsage(const Usage& usage) { _usage = usage; }
|
||||
Usage getUsage() const { return _usage; }
|
||||
|
@ -520,7 +500,7 @@ public:
|
|||
|
||||
ExternalUpdates getUpdates() const;
|
||||
|
||||
// Textures can be serialized directly to ktx data file, here is how
|
||||
// Textures can be serialized directly to ktx data file, here is how
|
||||
static ktx::KTXUniquePointer serialize(const Texture& texture);
|
||||
static Texture* unserialize(const std::string& ktxFile, TextureUsageType usageType = TextureUsageType::RESOURCE, Usage usage = Usage(), const Sampler::Desc& sampler = Sampler::Desc());
|
||||
static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header);
|
||||
|
@ -545,7 +525,7 @@ protected:
|
|||
Sampler _sampler;
|
||||
Stamp _samplerStamp { 0 };
|
||||
|
||||
uint32 _size { 0 };
|
||||
Size _size { 0 };
|
||||
Element _texelFormat;
|
||||
|
||||
uint16 _width { 1 };
|
||||
|
@ -553,9 +533,14 @@ protected:
|
|||
uint16 _depth { 1 };
|
||||
|
||||
uint16 _numSamples { 1 };
|
||||
uint16 _numSlices { 0 }; // if _numSlices is 0, the texture is not an "Array", the getNumSlices reported is 1
|
||||
|
||||
uint16 _maxMip { 0 };
|
||||
// if _numSlices is 0, the texture is not an "Array", the getNumSlices reported is 1
|
||||
uint16 _numSlices { 0 };
|
||||
|
||||
// valid _maxMipLevel is in the range [ 0 if no sub mips, log2(max(width, height, depth) ]
|
||||
// The num of mips returned is _maxMipLevel + 1
|
||||
uint16 _maxMipLevel { 0 };
|
||||
|
||||
uint16 _minMip { 0 };
|
||||
|
||||
Type _type { TEX_1D };
|
||||
|
@ -567,9 +552,9 @@ protected:
|
|||
bool _isIrradianceValid = false;
|
||||
bool _defined = false;
|
||||
|
||||
static Texture* create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler);
|
||||
static Texture* create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips, const Sampler& sampler);
|
||||
|
||||
Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
|
||||
Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips);
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Texture> TexturePointer;
|
||||
|
|
|
@ -128,7 +128,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
|
|||
}
|
||||
|
||||
// Number level of mips coming
|
||||
header.numberOfMipmapLevels = texture.getNumMipLevels();
|
||||
header.numberOfMipmapLevels = texture.getNumMips();
|
||||
|
||||
ktx::Images images;
|
||||
for (uint32_t level = 0; level < header.numberOfMipmapLevels; level++) {
|
||||
|
@ -224,6 +224,7 @@ Texture* Texture::unserialize(const std::string& ktxfile, TextureUsageType usage
|
|||
header.getPixelDepth(),
|
||||
1, // num Samples
|
||||
header.getNumberOfSlices(),
|
||||
header.getNumberOfLevels(),
|
||||
(isGPUKTXPayload ? gpuktxKeyValue._samplerDesc : sampler));
|
||||
|
||||
tex->setUsage((isGPUKTXPayload ? gpuktxKeyValue._usage : usage));
|
||||
|
|
|
@ -148,7 +148,7 @@ void Light::setAmbientSpherePreset(gpu::SphericalHarmonics::Preset preset) {
|
|||
void Light::setAmbientMap(gpu::TexturePointer ambientMap) {
|
||||
_ambientMap = ambientMap;
|
||||
if (ambientMap) {
|
||||
setAmbientMapNumMips(_ambientMap->evalNumMips());
|
||||
setAmbientMapNumMips(_ambientMap->getNumMips());
|
||||
} else {
|
||||
setAmbientMapNumMips(0);
|
||||
}
|
||||
|
|
|
@ -210,7 +210,7 @@ const QImage& image, bool isLinear, bool doCompress) {
|
|||
void generateMips(gpu::Texture* texture, QImage& image, bool fastResize) {
|
||||
#if CPU_MIPMAPS
|
||||
PROFILE_RANGE(resource_parse, "generateMips");
|
||||
auto numMips = texture->evalNumMips();
|
||||
auto numMips = texture->getNumMips();
|
||||
for (uint16 level = 1; level < numMips; ++level) {
|
||||
QSize mipSize(texture->evalMipWidth(level), texture->evalMipHeight(level));
|
||||
if (fastResize) {
|
||||
|
@ -230,7 +230,7 @@ void generateMips(gpu::Texture* texture, QImage& image, bool fastResize) {
|
|||
void generateFaceMips(gpu::Texture* texture, QImage& image, uint8 face) {
|
||||
#if CPU_MIPMAPS
|
||||
PROFILE_RANGE(resource_parse, "generateFaceMips");
|
||||
auto numMips = texture->evalNumMips();
|
||||
auto numMips = texture->getNumMips();
|
||||
for (uint16 level = 1; level < numMips; ++level) {
|
||||
QSize mipSize(texture->evalMipWidth(level), texture->evalMipHeight(level));
|
||||
QImage mipImage = image.scaled(mipSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
|
@ -255,9 +255,9 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag
|
|||
defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress);
|
||||
|
||||
if (isStrict) {
|
||||
theTexture = (gpu::Texture::createStrict(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture = (gpu::Texture::createStrict(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
} else {
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
}
|
||||
theTexture->setSource(srcImageName);
|
||||
auto usage = gpu::Texture::Usage::Builder().withColor();
|
||||
|
@ -317,7 +317,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src
|
|||
gpu::Element formatMip = gpu::Element::COLOR_BGRA_32;
|
||||
gpu::Element formatGPU = gpu::Element::COLOR_RGBA_32;
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->setSource(srcImageName);
|
||||
theTexture->setStoredMipFormat(formatMip);
|
||||
theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
|
@ -345,8 +345,8 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
|
|||
PROFILE_RANGE(resource_parse, "createNormalTextureFromBumpImage");
|
||||
QImage image = processSourceImage(srcImage, false);
|
||||
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
if (image.format() != QImage::Format_Grayscale8) {
|
||||
image = image.convertToFormat(QImage::Format_Grayscale8);
|
||||
}
|
||||
|
||||
// PR 5540 by AlessandroSigna integrated here as a specialized TextureLoader for bumpmaps
|
||||
|
@ -395,7 +395,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
|
|||
glm::normalize(v);
|
||||
|
||||
// convert to rgb from the value obtained computing the filter
|
||||
QRgb qRgbValue = qRgba(mapComponent(v.x), mapComponent(v.y), mapComponent(v.z), 1.0);
|
||||
QRgb qRgbValue = qRgba(mapComponent(v.z), mapComponent(v.y), mapComponent(v.x), 1.0);
|
||||
result.setPixel(i, j, qRgbValue);
|
||||
}
|
||||
}
|
||||
|
@ -407,7 +407,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
|
|||
gpu::Element formatGPU = gpu::Element::COLOR_RGBA_32;
|
||||
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, result.width(), result.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, result.width(), result.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->setSource(srcImageName);
|
||||
theTexture->setStoredMipFormat(formatMip);
|
||||
theTexture->assignStoredMip(0, result.byteCount(), result.constBits());
|
||||
|
@ -443,7 +443,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma
|
|||
#endif
|
||||
gpu::Element formatMip = gpu::Element::COLOR_R_8;
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->setSource(srcImageName);
|
||||
theTexture->setStoredMipFormat(formatMip);
|
||||
theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
|
@ -483,7 +483,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s
|
|||
#endif
|
||||
gpu::Element formatMip = gpu::Element::COLOR_R_8;
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->setSource(srcImageName);
|
||||
theTexture->setStoredMipFormat(formatMip);
|
||||
theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
|
@ -520,7 +520,7 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag
|
|||
#endif
|
||||
gpu::Element formatMip = gpu::Element::COLOR_R_8;
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->setSource(srcImageName);
|
||||
theTexture->setStoredMipFormat(formatMip);
|
||||
theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
|
@ -836,7 +836,7 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
|
|||
|
||||
// If the 6 faces have been created go on and define the true Texture
|
||||
if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {
|
||||
theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
theTexture->setSource(srcImageName);
|
||||
theTexture->setStoredMipFormat(formatMip);
|
||||
int f = 0;
|
||||
|
@ -848,11 +848,6 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
|
|||
f++;
|
||||
}
|
||||
|
||||
if (generateMips) {
|
||||
PROFILE_RANGE(resource_parse, "generateMips");
|
||||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
|
||||
// Generate irradiance while we are at it
|
||||
if (generateIrradiance) {
|
||||
PROFILE_RANGE(resource_parse, "generateIrradiance");
|
||||
|
|
|
@ -325,7 +325,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
|
|||
auto gpuTexture = _channels[i]->getGPUTexture();
|
||||
if (gpuTexture) {
|
||||
gpuTexture->setSampler(sampler);
|
||||
gpuTexture->autoGenerateMips(-1);
|
||||
gpuTexture->setAutoGenerateMips(true);
|
||||
}
|
||||
batch.setResourceTexture((gpu::uint32)i, gpuTexture);
|
||||
}
|
||||
|
|
|
@ -74,11 +74,11 @@ void AmbientOcclusionFramebuffer::allocate() {
|
|||
auto width = _frameSize.x;
|
||||
auto height = _frameSize.y;
|
||||
|
||||
_occlusionTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_occlusionTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion"));
|
||||
_occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture);
|
||||
|
||||
_occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred"));
|
||||
_occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
|
|||
_antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("antialiasing"));
|
||||
auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get<FramebufferCache>()->getLightingTexture()->getTexelFormat();
|
||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||
_antialiasingTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(format, width, height, defaultSampler));
|
||||
_antialiasingTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
|
||||
_antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,9 +53,9 @@ void DeferredFramebuffer::allocate() {
|
|||
|
||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||
|
||||
_deferredColorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, width, height, defaultSampler));
|
||||
_deferredNormalTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(linearFormat, width, height, defaultSampler));
|
||||
_deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, width, height, defaultSampler));
|
||||
_deferredColorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
|
||||
_deferredNormalTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(linearFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
|
||||
_deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
|
||||
|
||||
_deferredFramebuffer->setRenderBuffer(0, _deferredColorTexture);
|
||||
_deferredFramebuffer->setRenderBuffer(1, _deferredNormalTexture);
|
||||
|
@ -65,7 +65,7 @@ void DeferredFramebuffer::allocate() {
|
|||
|
||||
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
|
||||
if (!_primaryDepthTexture) {
|
||||
_primaryDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, width, height, defaultSampler));
|
||||
_primaryDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
|
||||
}
|
||||
|
||||
_deferredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
@ -75,7 +75,7 @@ void DeferredFramebuffer::allocate() {
|
|||
|
||||
auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR);
|
||||
|
||||
_lightingTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, defaultSampler));
|
||||
_lightingTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
|
||||
_lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("lighting"));
|
||||
_lightingFramebuffer->setRenderBuffer(0, _lightingTexture);
|
||||
_lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
|
|
@ -496,14 +496,14 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con
|
|||
auto colorFormat = gpu::Element::COLOR_SRGBA_32;
|
||||
|
||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||
auto primaryColorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, defaultSampler));
|
||||
auto primaryColorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler));
|
||||
|
||||
|
||||
_primaryFramebuffer->setRenderBuffer(0, primaryColorTexture);
|
||||
|
||||
|
||||
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
|
||||
auto primaryDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, defaultSampler));
|
||||
auto primaryDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler));
|
||||
|
||||
_primaryFramebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat);
|
||||
}
|
||||
|
|
|
@ -168,8 +168,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
|
|||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture());
|
||||
}
|
||||
|
||||
// Roughness map
|
||||
|
@ -182,8 +180,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
|
|||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
|
||||
}
|
||||
|
||||
// Normal map
|
||||
|
@ -196,8 +192,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
|
|||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, nullptr);
|
||||
}
|
||||
|
||||
// Metallic map
|
||||
|
@ -210,8 +204,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
|
|||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, nullptr);
|
||||
}
|
||||
|
||||
// Occlusion map
|
||||
|
@ -224,8 +216,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
|
|||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, nullptr);
|
||||
}
|
||||
|
||||
// Scattering map
|
||||
|
@ -238,8 +228,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
|
|||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, nullptr);
|
||||
}
|
||||
|
||||
// Emissive / Lightmap
|
||||
|
@ -259,8 +247,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
|
|||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,11 +73,11 @@ void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const Rend
|
|||
|
||||
auto colorFormat = gpu::Element::COLOR_SRGBA_32;
|
||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||
auto colorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, frameSize.x, frameSize.y, defaultSampler));
|
||||
auto colorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler));
|
||||
_framebuffer->setRenderBuffer(0, colorTexture);
|
||||
|
||||
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
|
||||
auto depthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, frameSize.x, frameSize.y, defaultSampler));
|
||||
auto depthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler));
|
||||
_framebuffer->setDepthStencilBuffer(depthTexture, depthFormat);
|
||||
}
|
||||
|
||||
|
|
|
@ -414,7 +414,7 @@ gpu::TexturePointer SubsurfaceScatteringResource::generateScatteringProfile(Rend
|
|||
const int PROFILE_RESOLUTION = 512;
|
||||
// const auto pixelFormat = gpu::Element::COLOR_SRGBA_32;
|
||||
const auto pixelFormat = gpu::Element::COLOR_R11G11B10;
|
||||
auto profileMap = gpu::TexturePointer(gpu::Texture::createRenderBuffer(pixelFormat, PROFILE_RESOLUTION, 1, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)));
|
||||
auto profileMap = gpu::TexturePointer(gpu::Texture::createRenderBuffer(pixelFormat, PROFILE_RESOLUTION, 1, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)));
|
||||
profileMap->setSource("Generated Scattering Profile");
|
||||
diffuseProfileGPU(profileMap, args);
|
||||
return profileMap;
|
||||
|
@ -425,7 +425,7 @@ gpu::TexturePointer SubsurfaceScatteringResource::generatePreIntegratedScatterin
|
|||
const int TABLE_RESOLUTION = 512;
|
||||
// const auto pixelFormat = gpu::Element::COLOR_SRGBA_32;
|
||||
const auto pixelFormat = gpu::Element::COLOR_R11G11B10;
|
||||
auto scatteringLUT = gpu::TexturePointer(gpu::Texture::createRenderBuffer(pixelFormat, TABLE_RESOLUTION, TABLE_RESOLUTION, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)));
|
||||
auto scatteringLUT = gpu::TexturePointer(gpu::Texture::createRenderBuffer(pixelFormat, TABLE_RESOLUTION, TABLE_RESOLUTION, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)));
|
||||
//diffuseScatter(scatteringLUT);
|
||||
scatteringLUT->setSource("Generated pre-integrated scattering");
|
||||
diffuseScatterGPU(profile, scatteringLUT, args);
|
||||
|
@ -434,7 +434,7 @@ gpu::TexturePointer SubsurfaceScatteringResource::generatePreIntegratedScatterin
|
|||
|
||||
gpu::TexturePointer SubsurfaceScatteringResource::generateScatteringSpecularBeckmann(RenderArgs* args) {
|
||||
const int SPECULAR_RESOLUTION = 256;
|
||||
auto beckmannMap = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32 /*gpu::Element(gpu::SCALAR, gpu::HALF, gpu::RGB)*/, SPECULAR_RESOLUTION, SPECULAR_RESOLUTION, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)));
|
||||
auto beckmannMap = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, SPECULAR_RESOLUTION, SPECULAR_RESOLUTION, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)));
|
||||
beckmannMap->setSource("Generated beckmannMap");
|
||||
computeSpecularBeckmannGPU(beckmannMap, args);
|
||||
return beckmannMap;
|
||||
|
|
|
@ -72,18 +72,18 @@ void LinearDepthFramebuffer::allocate() {
|
|||
auto height = _frameSize.y;
|
||||
|
||||
// For Linear Depth:
|
||||
_linearDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height,
|
||||
_linearDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, gpu::Texture::SINGLE_MIP,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth"));
|
||||
_linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture);
|
||||
_linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat());
|
||||
|
||||
// For Downsampling:
|
||||
_halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y,
|
||||
const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5;
|
||||
_halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_halfLinearDepthTexture->autoGenerateMips(5);
|
||||
|
||||
_halfNormalTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y,
|
||||
_halfNormalTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
|
||||
_downsampleFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("halfLinearDepth"));
|
||||
|
@ -304,15 +304,15 @@ void SurfaceGeometryFramebuffer::allocate() {
|
|||
auto width = _frameSize.x;
|
||||
auto height = _frameSize.y;
|
||||
|
||||
_curvatureTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_curvatureTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_curvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("surfaceGeometry::curvature"));
|
||||
_curvatureFramebuffer->setRenderBuffer(0, _curvatureTexture);
|
||||
|
||||
_lowCurvatureTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_lowCurvatureTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_lowCurvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("surfaceGeometry::lowCurvature"));
|
||||
_lowCurvatureFramebuffer->setRenderBuffer(0, _lowCurvatureTexture);
|
||||
|
||||
_blurringTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_blurringTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_blurringFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("surfaceGeometry::blurring"));
|
||||
_blurringFramebuffer->setRenderBuffer(0, _blurringTexture);
|
||||
}
|
||||
|
|
|
@ -21,17 +21,17 @@ out vec4 outLinearDepth;
|
|||
out vec4 outNormal;
|
||||
|
||||
void main(void) {
|
||||
// Gather 2 by 2 quads from texture
|
||||
// Gather 2 by 2 quads from texture and downsample
|
||||
|
||||
// Try different filters for Z
|
||||
//vec4 Zeyes = textureGather(linearDepthMap, varTexCoord0, 0);
|
||||
//float Zeye = min(min(Zeyes.x, Zeyes.y), min(Zeyes.z, Zeyes.w));
|
||||
float Zeye = texture(linearDepthMap, varTexCoord0).x;
|
||||
vec4 Zeyes = textureGather(linearDepthMap, varTexCoord0, 0);
|
||||
// float Zeye = texture(linearDepthMap, varTexCoord0).x;
|
||||
|
||||
vec4 rawNormalsX = textureGather(normalMap, varTexCoord0, 0);
|
||||
vec4 rawNormalsY = textureGather(normalMap, varTexCoord0, 1);
|
||||
vec4 rawNormalsZ = textureGather(normalMap, varTexCoord0, 2);
|
||||
|
||||
float Zeye = min(min(Zeyes.x, Zeyes.y), min(Zeyes.z, Zeyes.w));
|
||||
|
||||
vec3 normal = vec3(0.0);
|
||||
normal += unpackNormal(vec3(rawNormalsX[0], rawNormalsY[0], rawNormalsZ[0]));
|
||||
|
|
|
@ -207,7 +207,7 @@ void Font::read(QIODevice& in) {
|
|||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::BGRA);
|
||||
}
|
||||
_texture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(),
|
||||
_texture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::SINGLE_MIP,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR)));
|
||||
_texture->setStoredMipFormat(formatMip);
|
||||
_texture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
|
|
|
@ -108,7 +108,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
|
|||
// _blurredFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat());
|
||||
//}
|
||||
auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT);
|
||||
auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), blurringSampler));
|
||||
auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler));
|
||||
_blurredFramebuffer->setRenderBuffer(0, blurringTarget);
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
|
|||
_outputFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat());
|
||||
}*/
|
||||
auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT);
|
||||
auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), blurringSampler));
|
||||
auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler));
|
||||
_outputFramebuffer->setRenderBuffer(0, blurringTarget);
|
||||
}
|
||||
|
||||
|
|
|
@ -494,7 +494,7 @@ void OpenVrDisplayPlugin::customizeContext() {
|
|||
_compositeInfos[0].texture = _compositeFramebuffer->getRenderBuffer(0);
|
||||
for (size_t i = 0; i < COMPOSITING_BUFFER_SIZE; ++i) {
|
||||
if (0 != i) {
|
||||
_compositeInfos[i].texture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _renderTargetSize.x, _renderTargetSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT)));
|
||||
_compositeInfos[i].texture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _renderTargetSize.x, _renderTargetSize.y, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT)));
|
||||
}
|
||||
_compositeInfos[i].textureID = getGLBackend()->getTextureID(_compositeInfos[i].texture);
|
||||
}
|
||||
|
|
|
@ -1181,7 +1181,7 @@ function MyController(hand) {
|
|||
|
||||
this.updateStylusTip();
|
||||
|
||||
var DEFAULT_USE_FINGER_AS_STYLUS = true;
|
||||
var DEFAULT_USE_FINGER_AS_STYLUS = false;
|
||||
var USE_FINGER_AS_STYLUS = Settings.getValue("preferAvatarFingerOverStylus");
|
||||
if (USE_FINGER_AS_STYLUS === "") {
|
||||
USE_FINGER_AS_STYLUS = DEFAULT_USE_FINGER_AS_STYLUS;
|
||||
|
|
|
@ -81,6 +81,19 @@ body {
|
|||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* HACK
|
||||
Makes entity properties dialog's scrollbar work on tablet such that don't need to keep pointer within scrollbar width when
|
||||
using scroll handle.
|
||||
*/
|
||||
body {
|
||||
padding-right: 0;
|
||||
margin-right: -21px;
|
||||
}
|
||||
body > * {
|
||||
margin-right: 42px;
|
||||
}
|
||||
/* END OF HACK */
|
||||
|
||||
table {
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 15px;
|
||||
|
|
|
@ -5,6 +5,93 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
*/
|
||||
|
||||
/*
|
||||
CSS rules copied from edit-style.css.
|
||||
Edit-style.css is not used in its entirety because don't want custom scrollbars; default scrollbar styling is used in order
|
||||
to match other marketplace pages.
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: Raleway-Regular;
|
||||
src: url(../../../../resources/fonts/Raleway-Regular.ttf), /* Windows production */
|
||||
url(../../../../fonts/Raleway-Regular.ttf), /* OSX production */
|
||||
url(../../../../interface/resources/fonts/Raleway-Regular.ttf); /* Development, running script in /HiFi/examples */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Raleway-Bold;
|
||||
src: url(../../../../resources/fonts/Raleway-Bold.ttf),
|
||||
url(../../../../fonts/Raleway-Bold.ttf),
|
||||
url(../../../../interface/resources/fonts/Raleway-Bold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Raleway-SemiBold;
|
||||
src: url(../../../../resources/fonts/Raleway-SemiBold.ttf),
|
||||
url(../../../../fonts/Raleway-SemiBold.ttf),
|
||||
url(../../../../interface/resources/fonts/Raleway-SemiBold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: FiraSans-SemiBold;
|
||||
src: url(../../../../resources/fonts/FiraSans-SemiBold.ttf),
|
||||
url(../../../../fonts/FiraSans-SemiBold.ttf),
|
||||
url(../../../../interface/resources/fonts/FiraSans-SemiBold.ttf);
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 21px 21px 21px 21px;
|
||||
|
||||
color: #afafaf;
|
||||
background-color: #404040;
|
||||
font-family: Raleway-Regular;
|
||||
font-size: 15px;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
input[type=button] {
|
||||
font-family: Raleway-Bold;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
vertical-align: top;
|
||||
height: 28px;
|
||||
min-width: 120px;
|
||||
padding: 0px 18px;
|
||||
margin-right: 6px;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
background: linear-gradient(#343434 20%, #000 100%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type=button].blue {
|
||||
color: #fff;
|
||||
background-color: #1080b8;
|
||||
background: linear-gradient(#00b4ef 20%, #1080b8 100%);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Marketplaces-specific CSS.
|
||||
*/
|
||||
|
||||
body {
|
||||
background: white;
|
||||
padding: 0 0 0 0;
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
<head>
|
||||
<title>Marketplaces</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/edit-style.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/marketplaces.css">
|
||||
<script src="js/jquery-2.1.4.min.js"></script>
|
||||
</head>
|
||||
|
|
|
@ -72,7 +72,7 @@ function showMarketplace() {
|
|||
tablet.webEventReceived.connect(function (message) {
|
||||
|
||||
if (message === GOTO_DIRECTORY) {
|
||||
tablet.gotoWebScreen(MARKETPLACES_URL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
tablet.gotoWebScreen(MARKETPLACES_URL, injectURL);
|
||||
}
|
||||
|
||||
if (message === QUERY_CAN_WRITE_ASSETS) {
|
||||
|
|
|
@ -15,95 +15,94 @@
|
|||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
if (typeof String.prototype.startsWith != 'function') {
|
||||
String.prototype.startsWith = function (str){
|
||||
return this.slice(0, str.length) == str;
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof String.prototype.endsWith != 'function') {
|
||||
String.prototype.endsWith = function (str){
|
||||
return this.slice(-str.length) == str;
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof String.prototype.trimStartsWith != 'function') {
|
||||
String.prototype.trimStartsWith = function (str){
|
||||
if (this.startsWith(str)) {
|
||||
return this.substr(str.length);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof String.prototype.trimEndsWith != 'function') {
|
||||
String.prototype.trimEndsWith = function (str){
|
||||
if (this.endsWith(str)) {
|
||||
return this.substr(0,this.length - str.length);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
const INPUT = "Input";
|
||||
const OUTPUT = "Output";
|
||||
function parseMenuItem(item) {
|
||||
const USE = "Use ";
|
||||
const FOR_INPUT = " for " + INPUT;
|
||||
const FOR_OUTPUT = " for " + OUTPUT;
|
||||
if (item.slice(0, USE.length) == USE) {
|
||||
if (item.slice(-FOR_INPUT.length) == FOR_INPUT) {
|
||||
return { device: item.slice(USE.length, -FOR_INPUT.length), mode: INPUT };
|
||||
} else if (item.slice(-FOR_OUTPUT.length) == FOR_OUTPUT) {
|
||||
return { device: item.slice(USE.length, -FOR_OUTPUT.length), mode: OUTPUT };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// VAR DEFINITIONS
|
||||
//
|
||||
var debugPrintStatements = true;
|
||||
const INPUT_DEVICE_SETTING = "audio_input_device";
|
||||
const OUTPUT_DEVICE_SETTING = "audio_output_device";
|
||||
var audioDevicesList = [];
|
||||
var wasHmdActive = false; // assume it's not active to start
|
||||
var switchedAudioInputToHMD = false;
|
||||
var switchedAudioOutputToHMD = false;
|
||||
var previousSelectedInputAudioDevice = "";
|
||||
var previousSelectedOutputAudioDevice = "";
|
||||
var skipMenuEvents = true;
|
||||
|
||||
var selectedInputMenu = "";
|
||||
var selectedOutputMenu = "";
|
||||
|
||||
var audioDevicesList = [];
|
||||
function setupAudioMenus() {
|
||||
removeAudioMenus();
|
||||
Menu.addSeparator("Audio", "Input Audio Device");
|
||||
|
||||
var inputDeviceSetting = Settings.getValue(INPUT_DEVICE_SETTING);
|
||||
var inputDevices = AudioDevice.getInputDevices();
|
||||
var selectedInputDevice = AudioDevice.getInputDevice();
|
||||
if (inputDevices.indexOf(inputDeviceSetting) != -1 && selectedInputDevice != inputDeviceSetting) {
|
||||
if (AudioDevice.setInputDevice(inputDeviceSetting)) {
|
||||
selectedInputDevice = inputDeviceSetting;
|
||||
}
|
||||
//
|
||||
// BEGIN FUNCTION DEFINITIONS
|
||||
//
|
||||
function debug() {
|
||||
if (debugPrintStatements) {
|
||||
print.apply(null, [].concat.apply(["selectAudioDevice.js:"], [].map.call(arguments, JSON.stringify)));
|
||||
}
|
||||
print("audio input devices: " + inputDevices);
|
||||
for(var i = 0; i < inputDevices.length; i++) {
|
||||
var thisDeviceSelected = (inputDevices[i] == selectedInputDevice);
|
||||
var menuItem = "Use " + inputDevices[i] + " for Input";
|
||||
}
|
||||
|
||||
|
||||
function setupAudioMenus() {
|
||||
// menu events can be triggered asynchronously; skip them for 200ms to avoid recursion and false switches
|
||||
skipMenuEvents = true;
|
||||
Script.setTimeout(function() { skipMenuEvents = false; }, 200);
|
||||
|
||||
removeAudioMenus();
|
||||
|
||||
// Setup audio input devices
|
||||
Menu.addSeparator("Audio", "Input Audio Device");
|
||||
var inputDevices = AudioDevice.getInputDevices();
|
||||
for (var i = 0; i < inputDevices.length; i++) {
|
||||
var audioDeviceMenuString = "Use " + inputDevices[i] + " for Input";
|
||||
Menu.addMenuItem({
|
||||
menuName: "Audio",
|
||||
menuItemName: menuItem,
|
||||
menuItemName: audioDeviceMenuString,
|
||||
isCheckable: true,
|
||||
isChecked: thisDeviceSelected
|
||||
isChecked: inputDevices[i] == AudioDevice.getInputDevice()
|
||||
});
|
||||
audioDevicesList.push(menuItem);
|
||||
if (thisDeviceSelected) {
|
||||
selectedInputMenu = menuItem;
|
||||
}
|
||||
audioDevicesList.push(audioDeviceMenuString);
|
||||
}
|
||||
|
||||
// Setup audio output devices
|
||||
Menu.addSeparator("Audio", "Output Audio Device");
|
||||
var outputDevices = AudioDevice.getOutputDevices();
|
||||
for (var i = 0; i < outputDevices.length; i++) {
|
||||
var audioDeviceMenuString = "Use " + outputDevices[i] + " for Output";
|
||||
Menu.addMenuItem({
|
||||
menuName: "Audio",
|
||||
menuItemName: audioDeviceMenuString,
|
||||
isCheckable: true,
|
||||
isChecked: outputDevices[i] == AudioDevice.getOutputDevice()
|
||||
});
|
||||
audioDevicesList.push(audioDeviceMenuString);
|
||||
}
|
||||
}
|
||||
|
||||
function checkDeviceMismatch() {
|
||||
var inputDeviceSetting = Settings.getValue(INPUT_DEVICE_SETTING);
|
||||
var interfaceInputDevice = AudioDevice.getInputDevice();
|
||||
if (interfaceInputDevice != inputDeviceSetting) {
|
||||
debug("Input Setting & Device mismatch! Input SETTING: " + inputDeviceSetting + "Input DEVICE IN USE: " + interfaceInputDevice);
|
||||
switchAudioDevice("Use " + inputDeviceSetting + " for Input");
|
||||
}
|
||||
|
||||
var outputDeviceSetting = Settings.getValue(OUTPUT_DEVICE_SETTING);
|
||||
var outputDevices = AudioDevice.getOutputDevices();
|
||||
var selectedOutputDevice = AudioDevice.getOutputDevice();
|
||||
if (outputDevices.indexOf(outputDeviceSetting) != -1 && selectedOutputDevice != outputDeviceSetting) {
|
||||
if (AudioDevice.setOutputDevice(outputDeviceSetting)) {
|
||||
selectedOutputDevice = outputDeviceSetting;
|
||||
}
|
||||
}
|
||||
print("audio output devices: " + outputDevices);
|
||||
for (var i = 0; i < outputDevices.length; i++) {
|
||||
var thisDeviceSelected = (outputDevices[i] == selectedOutputDevice);
|
||||
var menuItem = "Use " + outputDevices[i] + " for Output";
|
||||
Menu.addMenuItem({
|
||||
menuName: "Audio",
|
||||
menuItemName: menuItem,
|
||||
isCheckable: true,
|
||||
isChecked: thisDeviceSelected
|
||||
});
|
||||
audioDevicesList.push(menuItem);
|
||||
if (thisDeviceSelected) {
|
||||
selectedOutputMenu = menuItem;
|
||||
}
|
||||
var interfaceOutputDevice = AudioDevice.getOutputDevice();
|
||||
if (interfaceOutputDevice != outputDeviceSetting) {
|
||||
debug("Output Setting & Device mismatch! Output SETTING: " + outputDeviceSetting + "Output DEVICE IN USE: " + interfaceOutputDevice);
|
||||
switchAudioDevice("Use " + outputDeviceSetting + " for Output");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,130 +111,170 @@ function removeAudioMenus() {
|
|||
Menu.removeSeparator("Audio", "Output Audio Device");
|
||||
|
||||
for (var index = 0; index < audioDevicesList.length; index++) {
|
||||
Menu.removeMenuItem("Audio", audioDevicesList[index]);
|
||||
if (Menu.menuItemExists("Audio", audioDevicesList[index])) {
|
||||
Menu.removeMenuItem("Audio", audioDevicesList[index]);
|
||||
}
|
||||
}
|
||||
|
||||
Menu.removeMenu("Audio > Devices");
|
||||
|
||||
audioDevicesList = [];
|
||||
}
|
||||
|
||||
function onDevicechanged() {
|
||||
print("audio devices changed, removing Audio > Devices menu...");
|
||||
Menu.removeMenu("Audio > Devices");
|
||||
print("now setting up Audio > Devices menu");
|
||||
debug("System audio devices changed. Removing and replacing Audio Menus...");
|
||||
setupAudioMenus();
|
||||
checkDeviceMismatch();
|
||||
}
|
||||
|
||||
// Have a small delay before the menu's get setup and the audio devices can switch to the last selected ones
|
||||
Script.setTimeout(function () {
|
||||
print("connecting deviceChanged");
|
||||
AudioDevice.deviceChanged.connect(onDevicechanged);
|
||||
print("setting up Audio > Devices menu for first time");
|
||||
setupAudioMenus();
|
||||
}, 5000);
|
||||
|
||||
function scriptEnding() {
|
||||
Menu.removeMenu("Audio > Devices");
|
||||
function onMenuEvent(audioDeviceMenuString) {
|
||||
if (!skipMenuEvents) {
|
||||
switchAudioDevice(audioDeviceMenuString);
|
||||
}
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
function switchAudioDevice(audioDeviceMenuString) {
|
||||
// if the device is not plugged in, short-circuit
|
||||
if (!~audioDevicesList.indexOf(audioDeviceMenuString)) {
|
||||
return;
|
||||
}
|
||||
|
||||
function menuItemEvent(menuItem) {
|
||||
if (menuItem.startsWith("Use ")) {
|
||||
if (menuItem.endsWith(" for Output")) {
|
||||
var selectedDevice = menuItem.trimStartsWith("Use ").trimEndsWith(" for Output");
|
||||
print("output audio selection..." + selectedDevice);
|
||||
Menu.menuItemEvent.disconnect(menuItemEvent);
|
||||
Menu.setIsOptionChecked(selectedOutputMenu, false);
|
||||
selectedOutputMenu = menuItem;
|
||||
Menu.setIsOptionChecked(selectedOutputMenu, true);
|
||||
if (AudioDevice.setOutputDevice(selectedDevice)) {
|
||||
Settings.setValue(OUTPUT_DEVICE_SETTING, selectedDevice);
|
||||
}
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
} else if (menuItem.endsWith(" for Input")) {
|
||||
var selectedDevice = menuItem.trimStartsWith("Use ").trimEndsWith(" for Input");
|
||||
print("input audio selection..." + selectedDevice);
|
||||
Menu.menuItemEvent.disconnect(menuItemEvent);
|
||||
Menu.setIsOptionChecked(selectedInputMenu, false);
|
||||
selectedInputMenu = menuItem;
|
||||
Menu.setIsOptionChecked(selectedInputMenu, true);
|
||||
var selection = parseMenuItem(audioDeviceMenuString);
|
||||
if (!selection) {
|
||||
debug("Invalid Audio audioDeviceMenuString! Doesn't end with 'for Input' or 'for Output'");
|
||||
return;
|
||||
}
|
||||
|
||||
// menu events can be triggered asynchronously; skip them for 200ms to avoid recursion and false switches
|
||||
skipMenuEvents = true;
|
||||
Script.setTimeout(function() { skipMenuEvents = false; }, 200);
|
||||
|
||||
var selectedDevice = selection.device;
|
||||
if (selection.mode == INPUT) {
|
||||
var currentInputDevice = AudioDevice.getInputDevice();
|
||||
if (selectedDevice != currentInputDevice) {
|
||||
debug("Switching audio INPUT device from " + currentInputDevice + " to " + selectedDevice);
|
||||
Menu.setIsOptionChecked("Use " + currentInputDevice + " for Input", false);
|
||||
if (AudioDevice.setInputDevice(selectedDevice)) {
|
||||
Settings.setValue(INPUT_DEVICE_SETTING, selectedDevice);
|
||||
Menu.setIsOptionChecked(audioDeviceMenuString, true);
|
||||
} else {
|
||||
debug("Error setting audio input device!")
|
||||
Menu.setIsOptionChecked(audioDeviceMenuString, false);
|
||||
}
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
} else {
|
||||
debug("Selected input device is the same as the current input device!")
|
||||
Settings.setValue(INPUT_DEVICE_SETTING, selectedDevice);
|
||||
Menu.setIsOptionChecked(audioDeviceMenuString, true);
|
||||
AudioDevice.setInputDevice(selectedDevice); // Still try to force-set the device (in case the user's trying to forcefully debug an issue)
|
||||
}
|
||||
} else if (selection.mode == OUTPUT) {
|
||||
var currentOutputDevice = AudioDevice.getOutputDevice();
|
||||
if (selectedDevice != currentOutputDevice) {
|
||||
debug("Switching audio OUTPUT device from " + currentOutputDevice + " to " + selectedDevice);
|
||||
Menu.setIsOptionChecked("Use " + currentOutputDevice + " for Output", false);
|
||||
if (AudioDevice.setOutputDevice(selectedDevice)) {
|
||||
Settings.setValue(OUTPUT_DEVICE_SETTING, selectedDevice);
|
||||
Menu.setIsOptionChecked(audioDeviceMenuString, true);
|
||||
} else {
|
||||
debug("Error setting audio output device!")
|
||||
Menu.setIsOptionChecked(audioDeviceMenuString, false);
|
||||
}
|
||||
} else {
|
||||
debug("Selected output device is the same as the current output device!")
|
||||
Settings.setValue(OUTPUT_DEVICE_SETTING, selectedDevice);
|
||||
Menu.setIsOptionChecked(audioDeviceMenuString, true);
|
||||
AudioDevice.setOutputDevice(selectedDevice); // Still try to force-set the device (in case the user's trying to forcefully debug an issue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
function restoreAudio() {
|
||||
if (switchedAudioInputToHMD) {
|
||||
debug("Switching back from HMD preferred audio input to: " + previousSelectedInputAudioDevice);
|
||||
switchAudioDevice("Use " + previousSelectedInputAudioDevice + " for Input");
|
||||
switchedAudioInputToHMD = false;
|
||||
}
|
||||
if (switchedAudioOutputToHMD) {
|
||||
debug("Switching back from HMD preferred audio output to: " + previousSelectedOutputAudioDevice);
|
||||
switchAudioDevice("Use " + previousSelectedOutputAudioDevice + " for Output");
|
||||
switchedAudioOutputToHMD = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Some HMDs (like Oculus CV1) have a built in audio device. If they
|
||||
// do, then this function will handle switching to that device automatically
|
||||
// when you goActive with the HMD active.
|
||||
var wasHmdMounted = false; // assume it's un-mounted to start
|
||||
var switchedAudioInputToHMD = false;
|
||||
var switchedAudioOutputToHMD = false;
|
||||
var previousSelectedInputAudioDevice = "";
|
||||
var previousSelectedOutputAudioDevice = "";
|
||||
|
||||
function restoreAudio() {
|
||||
if (switchedAudioInputToHMD) {
|
||||
print("switching back from HMD preferred audio input to:" + previousSelectedInputAudioDevice);
|
||||
menuItemEvent("Use " + previousSelectedInputAudioDevice + " for Input");
|
||||
}
|
||||
if (switchedAudioOutputToHMD) {
|
||||
print("switching back from HMD preferred audio output to:" + previousSelectedOutputAudioDevice);
|
||||
menuItemEvent("Use " + previousSelectedOutputAudioDevice + " for Output");
|
||||
}
|
||||
}
|
||||
|
||||
function checkHMDAudio() {
|
||||
// Mounted state is changing... handle switching
|
||||
if (HMD.mounted != wasHmdMounted) {
|
||||
print("HMD mounted changed...");
|
||||
// HMD Active state is changing; handle switching
|
||||
if (HMD.active != wasHmdActive) {
|
||||
debug("HMD Active state changed!");
|
||||
|
||||
// We're putting the HMD on... switch to those devices
|
||||
if (HMD.mounted) {
|
||||
print("NOW mounted...");
|
||||
// We're putting the HMD on; switch to those devices
|
||||
if (HMD.active) {
|
||||
debug("HMD is now Active.");
|
||||
var hmdPreferredAudioInput = HMD.preferredAudioInput();
|
||||
var hmdPreferredAudioOutput = HMD.preferredAudioOutput();
|
||||
print("hmdPreferredAudioInput:" + hmdPreferredAudioInput);
|
||||
print("hmdPreferredAudioOutput:" + hmdPreferredAudioOutput);
|
||||
debug("hmdPreferredAudioInput: " + hmdPreferredAudioInput);
|
||||
debug("hmdPreferredAudioOutput: " + hmdPreferredAudioOutput);
|
||||
|
||||
|
||||
var hmdHasPreferredAudio = (hmdPreferredAudioInput !== "") || (hmdPreferredAudioOutput !== "");
|
||||
if (hmdHasPreferredAudio) {
|
||||
print("HMD has preferred audio!");
|
||||
if (hmdPreferredAudioInput !== "") {
|
||||
debug("HMD has preferred audio input device.");
|
||||
previousSelectedInputAudioDevice = Settings.getValue(INPUT_DEVICE_SETTING);
|
||||
previousSelectedOutputAudioDevice = Settings.getValue(OUTPUT_DEVICE_SETTING);
|
||||
print("previousSelectedInputAudioDevice:" + previousSelectedInputAudioDevice);
|
||||
print("previousSelectedOutputAudioDevice:" + previousSelectedOutputAudioDevice);
|
||||
if (hmdPreferredAudioInput != previousSelectedInputAudioDevice && hmdPreferredAudioInput !== "") {
|
||||
print("switching to HMD preferred audio input to:" + hmdPreferredAudioInput);
|
||||
debug("previousSelectedInputAudioDevice: " + previousSelectedInputAudioDevice);
|
||||
if (hmdPreferredAudioInput != previousSelectedInputAudioDevice) {
|
||||
switchedAudioInputToHMD = true;
|
||||
menuItemEvent("Use " + hmdPreferredAudioInput + " for Input");
|
||||
switchAudioDevice("Use " + hmdPreferredAudioInput + " for Input");
|
||||
}
|
||||
if (hmdPreferredAudioOutput != previousSelectedOutputAudioDevice && hmdPreferredAudioOutput !== "") {
|
||||
print("switching to HMD preferred audio output to:" + hmdPreferredAudioOutput);
|
||||
}
|
||||
if (hmdPreferredAudioOutput !== "") {
|
||||
debug("HMD has preferred audio output device.");
|
||||
previousSelectedOutputAudioDevice = Settings.getValue(OUTPUT_DEVICE_SETTING);
|
||||
debug("previousSelectedOutputAudioDevice: " + previousSelectedOutputAudioDevice);
|
||||
if (hmdPreferredAudioOutput != previousSelectedOutputAudioDevice) {
|
||||
switchedAudioOutputToHMD = true;
|
||||
menuItemEvent("Use " + hmdPreferredAudioOutput + " for Output");
|
||||
switchAudioDevice("Use " + hmdPreferredAudioOutput + " for Output");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print("HMD NOW un-mounted...");
|
||||
debug("HMD no longer active. Restoring audio I/O devices...");
|
||||
restoreAudio();
|
||||
}
|
||||
}
|
||||
wasHmdMounted = HMD.mounted;
|
||||
wasHmdActive = HMD.active;
|
||||
}
|
||||
|
||||
Script.update.connect(checkHMDAudio);
|
||||
//
|
||||
// END FUNCTION DEFINITIONS
|
||||
//
|
||||
|
||||
//
|
||||
// BEGIN SCRIPT BODY
|
||||
//
|
||||
// Wait for the C++ systems to fire up before trying to do anything with audio devices
|
||||
Script.setTimeout(function () {
|
||||
debug("Connecting deviceChanged(), displayModeChanged(), and switchAudioDevice()...");
|
||||
AudioDevice.deviceChanged.connect(onDevicechanged);
|
||||
HMD.displayModeChanged.connect(checkHMDAudio);
|
||||
Menu.menuItemEvent.connect(onMenuEvent);
|
||||
debug("Setting up Audio I/O menu for the first time...");
|
||||
setupAudioMenus();
|
||||
checkDeviceMismatch();
|
||||
debug("Checking HMD audio status...")
|
||||
checkHMDAudio();
|
||||
}, 3000);
|
||||
|
||||
debug("Connecting scriptEnding()");
|
||||
Script.scriptEnding.connect(function () {
|
||||
restoreAudio();
|
||||
removeAudioMenus();
|
||||
Menu.menuItemEvent.disconnect(menuItemEvent);
|
||||
Script.update.disconnect(checkHMDAudio);
|
||||
Menu.menuItemEvent.disconnect(onMenuEvent);
|
||||
HMD.displayModeChanged.disconnect(checkHMDAudio);
|
||||
AudioDevice.deviceChanged.disconnect(onDevicechanged);
|
||||
});
|
||||
|
||||
//
|
||||
// END SCRIPT BODY
|
||||
//
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
Loading…
Reference in a new issue