mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 07:57:30 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
7c5961ea63
43 changed files with 618 additions and 338 deletions
|
@ -35,8 +35,32 @@
|
||||||
function onRowClicked(e) {
|
function onRowClicked(e) {
|
||||||
var id = this.dataset.entityId;
|
var id = this.dataset.entityId;
|
||||||
var selection = [this.dataset.entityId];
|
var selection = [this.dataset.entityId];
|
||||||
if (e.shiftKey) {
|
if (e.ctrlKey) {
|
||||||
selection = selection.concat(selectedEntities);
|
selection = selection.concat(selectedEntities);
|
||||||
|
} else if (e.shiftKey && selectedEntities.length > 0) {
|
||||||
|
var previousItemFound = -1;
|
||||||
|
var clickedItemFound = -1;
|
||||||
|
for (var i in entityList.visibleItems) {
|
||||||
|
if (clickedItemFound === -1 && this.dataset.entityId == entityList.visibleItems[i].values().id) {
|
||||||
|
clickedItemFound = i;
|
||||||
|
} else if(previousItemFound === -1 && selectedEntities[0] == entityList.visibleItems[i].values().id) {
|
||||||
|
previousItemFound = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (previousItemFound !== -1 && clickedItemFound !== -1) {
|
||||||
|
var betweenItems = [];
|
||||||
|
var toItem = Math.max(previousItemFound, clickedItemFound);
|
||||||
|
// skip first and last item in this loop, we add them to selection after the loop
|
||||||
|
for (var i = (Math.min(previousItemFound, clickedItemFound) + 1); i < toItem; i++) {
|
||||||
|
entityList.visibleItems[i].elm.className = 'selected';
|
||||||
|
betweenItems.push(entityList.visibleItems[i].values().id);
|
||||||
|
}
|
||||||
|
if (previousItemFound > clickedItemFound) {
|
||||||
|
// always make sure that we add the items in the right order
|
||||||
|
betweenItems.reverse();
|
||||||
|
}
|
||||||
|
selection = selection.concat(betweenItems, selectedEntities);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedEntities = selection;
|
selectedEntities = selection;
|
||||||
|
@ -151,6 +175,17 @@
|
||||||
refreshEntities();
|
refreshEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener("keydown", function (e) {
|
||||||
|
if (e.target.nodeName === "INPUT") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var keyCode = e.keyCode;
|
||||||
|
if (keyCode === 46) {
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
||||||
|
refreshEntities();
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
if (window.EventBridge !== undefined) {
|
if (window.EventBridge !== undefined) {
|
||||||
EventBridge.scriptEventReceived.connect(function(data) {
|
EventBridge.scriptEventReceived.connect(function(data) {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
|
|
|
@ -875,6 +875,30 @@ void Application::paintGL() {
|
||||||
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
||||||
resizeGL();
|
resizeGL();
|
||||||
|
|
||||||
|
// Before anything else, let's sync up the gpuContext with the true glcontext used in case anything happened
|
||||||
|
renderArgs._context->syncCache();
|
||||||
|
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||||
|
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferDepthColor();
|
||||||
|
|
||||||
|
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
||||||
|
renderRearViewMirror(&renderArgs, _mirrorViewRect);
|
||||||
|
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
||||||
|
|
||||||
|
{
|
||||||
|
float ratio = ((float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale());
|
||||||
|
auto mirrorViewport = glm::ivec4(0, 0, _mirrorViewRect.width() * ratio, _mirrorViewRect.height() * ratio);
|
||||||
|
auto mirrorViewportDest = mirrorViewport;
|
||||||
|
|
||||||
|
auto selfieFbo = DependencyManager::get<FramebufferCache>()->getSelfieFramebuffer();
|
||||||
|
gpu::Batch batch;
|
||||||
|
batch.setFramebuffer(selfieFbo);
|
||||||
|
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||||
|
batch.blit(primaryFbo, mirrorViewport, selfieFbo, mirrorViewportDest);
|
||||||
|
batch.setFramebuffer(nullptr);
|
||||||
|
renderArgs._context->render(batch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("renderOverlay");
|
PerformanceTimer perfTimer("renderOverlay");
|
||||||
|
@ -892,6 +916,9 @@ void Application::paintGL() {
|
||||||
Application::getInstance()->cameraMenuChanged();
|
Application::getInstance()->cameraMenuChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The render mode is default or mirror if the camera is in mirror mode, assigned further below
|
||||||
|
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
||||||
|
|
||||||
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
||||||
// Always use the default eye position, not the actual head eye position.
|
// Always use the default eye position, not the actual head eye position.
|
||||||
// Using the latter will cause the camera to wobble with idle animations,
|
// Using the latter will cause the camera to wobble with idle animations,
|
||||||
|
@ -928,6 +955,7 @@ void Application::paintGL() {
|
||||||
glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) +
|
glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) +
|
||||||
(_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
|
(_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
|
||||||
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
||||||
|
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update camera position
|
// Update camera position
|
||||||
|
@ -935,12 +963,6 @@ void Application::paintGL() {
|
||||||
_myCamera.update(1.0f / _fps);
|
_myCamera.update(1.0f / _fps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync up the View Furstum with the camera
|
|
||||||
loadViewFrustum(_myCamera, _viewFrustum);
|
|
||||||
|
|
||||||
|
|
||||||
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
|
||||||
|
|
||||||
if (OculusManager::isConnected()) {
|
if (OculusManager::isConnected()) {
|
||||||
//When in mirror mode, use camera rotation. Otherwise, use body rotation
|
//When in mirror mode, use camera rotation. Otherwise, use body rotation
|
||||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||||
|
@ -952,47 +974,28 @@ void Application::paintGL() {
|
||||||
TV3DManager::display(&renderArgs, _myCamera);
|
TV3DManager::display(&renderArgs, _myCamera);
|
||||||
} else {
|
} else {
|
||||||
PROFILE_RANGE(__FUNCTION__ "/mainRender");
|
PROFILE_RANGE(__FUNCTION__ "/mainRender");
|
||||||
|
// Viewport is assigned to the size of the framebuffer
|
||||||
|
QSize size = DependencyManager::get<FramebufferCache>()->getFrameBufferSize();
|
||||||
|
renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height());
|
||||||
|
|
||||||
{
|
|
||||||
gpu::Batch batch;
|
|
||||||
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
|
|
||||||
batch.setFramebuffer(primaryFbo);
|
|
||||||
// clear the normal and specular buffers
|
|
||||||
batch.clearFramebuffer(
|
|
||||||
gpu::Framebuffer::BUFFER_COLOR0 |
|
|
||||||
gpu::Framebuffer::BUFFER_COLOR1 |
|
|
||||||
gpu::Framebuffer::BUFFER_COLOR2 |
|
|
||||||
gpu::Framebuffer::BUFFER_DEPTH,
|
|
||||||
vec4(vec3(0), 1), 1.0, 0.0);
|
|
||||||
|
|
||||||
// Viewport is assigned to the size of the framebuffer
|
|
||||||
QSize size = DependencyManager::get<FramebufferCache>()->getFrameBufferSize();
|
|
||||||
renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height());
|
|
||||||
batch.setViewportTransform(renderArgs._viewport);
|
|
||||||
renderArgs._context->render(batch);
|
|
||||||
}
|
|
||||||
|
|
||||||
displaySide(&renderArgs, _myCamera);
|
displaySide(&renderArgs, _myCamera);
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
|
||||||
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
|
||||||
renderRearViewMirror(&renderArgs, _mirrorViewRect);
|
|
||||||
renderArgs._renderMode = RenderArgs::NORMAL_RENDER_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
|
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferDepthColor();
|
||||||
gpu::Batch batch;
|
gpu::Batch batch;
|
||||||
batch.blit(primaryFbo, glm::ivec4(0, 0, _renderResolution.x, _renderResolution.y),
|
batch.blit(primaryFbo, glm::ivec4(0, 0, _renderResolution.x, _renderResolution.y),
|
||||||
nullptr, glm::ivec4(0, 0, _glWidget->getDeviceSize().width(), _glWidget->getDeviceSize().height()));
|
nullptr, glm::ivec4(0, 0, _glWidget->getDeviceSize().width(), _glWidget->getDeviceSize().height()));
|
||||||
|
|
||||||
|
batch.setFramebuffer(nullptr);
|
||||||
|
|
||||||
renderArgs._context->render(batch);
|
renderArgs._context->render(batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
_compositor.displayOverlayTexture(&renderArgs);
|
_compositor.displayOverlayTexture(&renderArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!OculusManager::isConnected() || OculusManager::allowSwap()) {
|
if (!OculusManager::isConnected() || OculusManager::allowSwap()) {
|
||||||
PROFILE_RANGE(__FUNCTION__ "/bufferSwap");
|
PROFILE_RANGE(__FUNCTION__ "/bufferSwap");
|
||||||
_glWidget->swapBuffers();
|
_glWidget->swapBuffers();
|
||||||
|
@ -1002,6 +1005,7 @@ void Application::paintGL() {
|
||||||
OculusManager::endFrameTiming();
|
OculusManager::endFrameTiming();
|
||||||
}
|
}
|
||||||
_frameCount++;
|
_frameCount++;
|
||||||
|
_numFramesSinceLastResize++;
|
||||||
Stats::getInstance()->setRenderDetails(renderArgs._details);
|
Stats::getInstance()->setRenderDetails(renderArgs._details);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1055,6 +1059,7 @@ void Application::resizeGL() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_renderResolution != toGlm(renderSize)) {
|
if (_renderResolution != toGlm(renderSize)) {
|
||||||
|
_numFramesSinceLastResize = 0;
|
||||||
_renderResolution = toGlm(renderSize);
|
_renderResolution = toGlm(renderSize);
|
||||||
DependencyManager::get<FramebufferCache>()->setFrameBufferSize(renderSize);
|
DependencyManager::get<FramebufferCache>()->setFrameBufferSize(renderSize);
|
||||||
|
|
||||||
|
@ -1068,7 +1073,6 @@ void Application::resizeGL() {
|
||||||
auto canvasSize = _glWidget->size();
|
auto canvasSize = _glWidget->size();
|
||||||
offscreenUi->resize(canvasSize);
|
offscreenUi->resize(canvasSize);
|
||||||
_glWidget->makeCurrent();
|
_glWidget->makeCurrent();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::importSVOFromURL(const QString& urlString) {
|
bool Application::importSVOFromURL(const QString& urlString) {
|
||||||
|
@ -1798,13 +1802,6 @@ void Application::idle() {
|
||||||
}
|
}
|
||||||
double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0;
|
double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0;
|
||||||
if (timeSinceLastUpdate > targetFramePeriod) {
|
if (timeSinceLastUpdate > targetFramePeriod) {
|
||||||
|
|
||||||
{
|
|
||||||
static const int IDLE_EVENT_PROCESS_MAX_TIME_MS = 2;
|
|
||||||
PerformanceTimer perfTimer("processEvents");
|
|
||||||
processEvents(QEventLoop::AllEvents, IDLE_EVENT_PROCESS_MAX_TIME_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastTimeUpdated.start();
|
_lastTimeUpdated.start();
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("update");
|
PerformanceTimer perfTimer("update");
|
||||||
|
@ -1836,12 +1833,8 @@ void Application::idle() {
|
||||||
// Once rendering is off on another thread we should be able to have Application::idle run at start(0) in
|
// Once rendering is off on another thread we should be able to have Application::idle run at start(0) in
|
||||||
// perpetuity and not expect events to get backed up.
|
// perpetuity and not expect events to get backed up.
|
||||||
|
|
||||||
static const int IDLE_TIMER_DELAY_MS = 0;
|
static const int IDLE_TIMER_DELAY_MS = 2;
|
||||||
int desiredInterval = _glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS;
|
idleTimer->start(_glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS);
|
||||||
|
|
||||||
if (idleTimer->interval() != desiredInterval) {
|
|
||||||
idleTimer->start(desiredInterval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for any requested background downloads.
|
// check for any requested background downloads.
|
||||||
|
@ -2493,10 +2486,18 @@ void Application::update(float deltaTime) {
|
||||||
_myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN));
|
_myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN));
|
||||||
_myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT));
|
_myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT));
|
||||||
_myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT));
|
_myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT));
|
||||||
_myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP));
|
if (deltaTime > FLT_EPSILON) {
|
||||||
_myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN));
|
// For rotations what we really want are meausures of "angles per second" (in order to prevent
|
||||||
_myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT));
|
// fps-dependent spin rates) so we need to scale the units of the controller contribution.
|
||||||
_myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT));
|
// (TODO?: maybe we should similarly scale ALL action state info, or change the expected behavior
|
||||||
|
// controllers to provide a delta_per_second value rather than a raw delta.)
|
||||||
|
const float EXPECTED_FRAME_RATE = 60.0f;
|
||||||
|
float timeFactor = EXPECTED_FRAME_RATE * deltaTime;
|
||||||
|
_myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP) / timeFactor);
|
||||||
|
_myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN) / timeFactor);
|
||||||
|
_myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT) / timeFactor);
|
||||||
|
_myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT) / timeFactor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_myAvatar->setDriveKeys(BOOM_IN, _userInputMapper.getActionState(UserInputMapper::BOOM_IN));
|
_myAvatar->setDriveKeys(BOOM_IN, _userInputMapper.getActionState(UserInputMapper::BOOM_IN));
|
||||||
_myAvatar->setDriveKeys(BOOM_OUT, _userInputMapper.getActionState(UserInputMapper::BOOM_OUT));
|
_myAvatar->setDriveKeys(BOOM_OUT, _userInputMapper.getActionState(UserInputMapper::BOOM_OUT));
|
||||||
|
@ -2961,35 +2962,25 @@ PickRay Application::computePickRay(float x, float y) const {
|
||||||
if (isHMDMode()) {
|
if (isHMDMode()) {
|
||||||
getApplicationCompositor().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
|
getApplicationCompositor().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
|
||||||
} else {
|
} else {
|
||||||
if (QThread::currentThread() == activeRenderingThread) {
|
getViewFrustum()->computePickRay(x, y, result.origin, result.direction);
|
||||||
getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction);
|
|
||||||
} else {
|
|
||||||
getViewFrustum()->computePickRay(x, y, result.origin, result.direction);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) {
|
QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) {
|
||||||
auto primaryFramebuffer = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer));
|
|
||||||
|
|
||||||
// clear the alpha channel so the background is transparent
|
|
||||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
|
|
||||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
|
|
||||||
|
|
||||||
const int BILLBOARD_SIZE = 64;
|
const int BILLBOARD_SIZE = 64;
|
||||||
// TODO: Pass a RenderArgs to renderAvatarBillboard
|
|
||||||
renderRearViewMirror(renderArgs, QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE,
|
|
||||||
BILLBOARD_SIZE, BILLBOARD_SIZE),
|
|
||||||
true);
|
|
||||||
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
|
|
||||||
glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
|
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
// Need to make sure the gl context is current here
|
||||||
|
_glWidget->makeCurrent();
|
||||||
|
|
||||||
|
renderArgs->_renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
||||||
|
renderRearViewMirror(renderArgs, QRect(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE), true);
|
||||||
|
|
||||||
|
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferDepthColor();
|
||||||
|
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
|
||||||
|
renderArgs->_context->downloadFramebuffer(primaryFbo, glm::ivec4(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE), image);
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3293,10 +3284,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
||||||
sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems);
|
sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems);
|
||||||
sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems);
|
sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems);
|
||||||
}
|
}
|
||||||
//Render the sixense lasers
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
|
|
||||||
_myAvatar->renderLaserPointers(*renderArgs->_batch);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!selfAvatarOnly) {
|
if (!selfAvatarOnly) {
|
||||||
// give external parties a change to hook in
|
// give external parties a change to hook in
|
||||||
|
@ -3402,36 +3389,20 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi
|
||||||
// set the bounds of rear mirror view
|
// set the bounds of rear mirror view
|
||||||
gpu::Vec4i viewport;
|
gpu::Vec4i viewport;
|
||||||
if (billboard) {
|
if (billboard) {
|
||||||
QSize size = DependencyManager::get<FramebufferCache>()->getFrameBufferSize();
|
viewport = gpu::Vec4i(0, 0, region.width(), region.height());
|
||||||
viewport = gpu::Vec4i(region.x(), size.height() - region.y() - region.height(), region.width(), region.height());
|
|
||||||
} else {
|
} else {
|
||||||
// if not rendering the billboard, the region is in device independent coordinates; must convert to device
|
// if not rendering the billboard, the region is in device independent coordinates; must convert to device
|
||||||
QSize size = DependencyManager::get<FramebufferCache>()->getFrameBufferSize();
|
|
||||||
float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale();
|
float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale();
|
||||||
int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio;
|
int width = region.width() * ratio;
|
||||||
viewport = gpu::Vec4i(x, size.height() - y - height, width, height);
|
int height = region.height() * ratio;
|
||||||
|
viewport = gpu::Vec4i(0, 0, width, height);
|
||||||
}
|
}
|
||||||
renderArgs->_viewport = viewport;
|
renderArgs->_viewport = viewport;
|
||||||
|
|
||||||
{
|
|
||||||
gpu::Batch batch;
|
|
||||||
batch.setViewportTransform(viewport);
|
|
||||||
batch.setStateScissorRect(viewport);
|
|
||||||
batch.clearFramebuffer(
|
|
||||||
gpu::Framebuffer::BUFFER_COLOR0 |
|
|
||||||
gpu::Framebuffer::BUFFER_COLOR1 |
|
|
||||||
gpu::Framebuffer::BUFFER_COLOR2 |
|
|
||||||
gpu::Framebuffer::BUFFER_DEPTH,
|
|
||||||
vec4(vec3(0), 1), 1.0, 0.0, true);
|
|
||||||
// Viewport is assigned to the size of the framebuffer
|
|
||||||
renderArgs->_context->render(batch);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render rear mirror view
|
// render rear mirror view
|
||||||
displaySide(renderArgs, _mirrorCamera, true, billboard);
|
displaySide(renderArgs, _mirrorCamera, true, billboard);
|
||||||
|
|
||||||
renderArgs->_viewport = originalViewport;
|
renderArgs->_viewport = originalViewport;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::resetSensors() {
|
void Application::resetSensors() {
|
||||||
|
|
|
@ -328,6 +328,8 @@ public:
|
||||||
|
|
||||||
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
|
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
|
||||||
|
|
||||||
|
const QRect& getMirrorViewRect() const { return _mirrorViewRect; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
/// Fired when we're simulating; allows external parties to hook in.
|
/// Fired when we're simulating; allows external parties to hook in.
|
||||||
|
@ -640,6 +642,7 @@ private:
|
||||||
Overlays _overlays;
|
Overlays _overlays;
|
||||||
ApplicationOverlay _applicationOverlay;
|
ApplicationOverlay _applicationOverlay;
|
||||||
ApplicationCompositor _compositor;
|
ApplicationCompositor _compositor;
|
||||||
|
int _numFramesSinceLastResize = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Application_h
|
#endif // hifi_Application_h
|
||||||
|
|
|
@ -252,8 +252,6 @@ Menu::Menu() {
|
||||||
avatar, SLOT(updateMotionBehavior()));
|
avatar, SLOT(updateMotionBehavior()));
|
||||||
|
|
||||||
MenuWrapper* viewMenu = addMenu("View");
|
MenuWrapper* viewMenu = addMenu("View");
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()));
|
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu,
|
addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||||
MenuOption::Fullscreen,
|
MenuOption::Fullscreen,
|
||||||
|
@ -478,7 +476,6 @@ Menu::Menu() {
|
||||||
qApp,
|
qApp,
|
||||||
SLOT(setLowVelocityFilter(bool)));
|
SLOT(setLowVelocityFilter(bool)));
|
||||||
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true);
|
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseLasers, 0, false);
|
|
||||||
|
|
||||||
MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion");
|
MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion");
|
||||||
addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false);
|
addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false);
|
||||||
|
@ -490,6 +487,7 @@ Menu::Menu() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MenuWrapper* networkMenu = developerMenu->addMenu("Network");
|
MenuWrapper* networkMenu = developerMenu->addMenu("Network");
|
||||||
|
addActionToQMenuAndActionHash(networkMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()));
|
||||||
addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false,
|
addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false,
|
||||||
qApp->getEntityEditPacketSender(),
|
qApp->getEntityEditPacketSender(),
|
||||||
SLOT(toggleNackPackets()));
|
SLOT(toggleNackPackets()));
|
||||||
|
|
|
@ -272,7 +272,6 @@ namespace MenuOption {
|
||||||
const QString SimpleShadows = "Simple";
|
const QString SimpleShadows = "Simple";
|
||||||
const QString SixenseEnabled = "Enable Hydra Support";
|
const QString SixenseEnabled = "Enable Hydra Support";
|
||||||
const QString SixenseMouseInput = "Enable Sixense Mouse Input";
|
const QString SixenseMouseInput = "Enable Sixense Mouse Input";
|
||||||
const QString SixenseLasers = "Enable Sixense UI Lasers";
|
|
||||||
const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations";
|
const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations";
|
||||||
const QString Stars = "Stars";
|
const QString Stars = "Stars";
|
||||||
const QString Stats = "Stats";
|
const QString Stats = "Stats";
|
||||||
|
|
|
@ -443,36 +443,57 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
||||||
_skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f);
|
_skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stack indicator spheres
|
|
||||||
float indicatorOffset = 0.0f;
|
|
||||||
if (!_displayName.isEmpty() && _displayNameAlpha != 0.0f) {
|
|
||||||
const float DISPLAY_NAME_INDICATOR_OFFSET = 0.22f;
|
|
||||||
indicatorOffset = DISPLAY_NAME_INDICATOR_OFFSET;
|
|
||||||
}
|
|
||||||
const float INDICATOR_RADIUS = 0.03f;
|
|
||||||
const float INDICATOR_INDICATOR_OFFSET = 3.0f * INDICATOR_RADIUS;
|
|
||||||
|
|
||||||
// If this is the avatar being looked at, render a little ball above their head
|
// If this is the avatar being looked at, render a little ball above their head
|
||||||
if (_isLookAtTarget && Menu::getInstance()->isOptionChecked(MenuOption::RenderFocusIndicator)) {
|
if (_isLookAtTarget && Menu::getInstance()->isOptionChecked(MenuOption::RenderFocusIndicator)) {
|
||||||
|
const float INDICATOR_OFFSET = 0.22f;
|
||||||
|
const float INDICATOR_RADIUS = 0.03f;
|
||||||
const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f };
|
const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f };
|
||||||
glm::vec3 position = glm::vec3(_position.x, getDisplayNamePosition().y + indicatorOffset, _position.z);
|
glm::vec3 position = glm::vec3(_position.x, getDisplayNamePosition().y + INDICATOR_OFFSET, _position.z);
|
||||||
Transform transform;
|
Transform transform;
|
||||||
transform.setTranslation(position);
|
transform.setTranslation(position);
|
||||||
batch.setModelTransform(transform);
|
batch.setModelTransform(transform);
|
||||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, INDICATOR_RADIUS,
|
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, INDICATOR_RADIUS,
|
||||||
15, 15, LOOK_AT_INDICATOR_COLOR);
|
15, 15, LOOK_AT_INDICATOR_COLOR);
|
||||||
indicatorOffset += INDICATOR_INDICATOR_OFFSET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the avatar is looking at me, render an indication that they area
|
// If the avatar is looking at me, indicate that they are
|
||||||
if (getHead()->getIsLookingAtMe() && Menu::getInstance()->isOptionChecked(MenuOption::ShowWhosLookingAtMe)) {
|
if (getHead()->isLookingAtMe() && Menu::getInstance()->isOptionChecked(MenuOption::ShowWhosLookingAtMe)) {
|
||||||
const glm::vec4 LOOKING_AT_ME_COLOR = { 0.8f, 0.65f, 0.0f, 0.1f };
|
const glm::vec3 LOOKING_AT_ME_COLOR = { 1.0f, 1.0f, 1.0f };
|
||||||
glm::vec3 position = glm::vec3(_position.x, getDisplayNamePosition().y + indicatorOffset, _position.z);
|
const float LOOKING_AT_ME_ALPHA_START = 0.8f;
|
||||||
Transform transform;
|
const float LOOKING_AT_ME_DURATION = 0.5f; // seconds
|
||||||
transform.setTranslation(position);
|
quint64 now = usecTimestampNow();
|
||||||
batch.setModelTransform(transform);
|
float alpha = LOOKING_AT_ME_ALPHA_START
|
||||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, INDICATOR_RADIUS,
|
* (1.0f - ((float)(now - getHead()->getLookingAtMeStarted()))
|
||||||
15, 15, LOOKING_AT_ME_COLOR);
|
/ (LOOKING_AT_ME_DURATION * (float)USECS_PER_SECOND));
|
||||||
|
if (alpha > 0.0f) {
|
||||||
|
QSharedPointer<NetworkGeometry> geometry = getHead()->getFaceModel().getGeometry();
|
||||||
|
if (geometry) {
|
||||||
|
const float DEFAULT_EYE_DIAMETER = 0.048f; // Typical human eye
|
||||||
|
const float RADIUS_INCREMENT = 0.005f;
|
||||||
|
Transform transform;
|
||||||
|
|
||||||
|
glm::vec3 position = getHead()->getLeftEyePosition();
|
||||||
|
transform.setTranslation(position);
|
||||||
|
batch.setModelTransform(transform);
|
||||||
|
float eyeDiameter = geometry->getFBXGeometry().leftEyeSize;
|
||||||
|
if (eyeDiameter == 0.0f) {
|
||||||
|
eyeDiameter = DEFAULT_EYE_DIAMETER;
|
||||||
|
}
|
||||||
|
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch,
|
||||||
|
eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT, 15, 15, glm::vec4(LOOKING_AT_ME_COLOR, alpha));
|
||||||
|
|
||||||
|
position = getHead()->getRightEyePosition();
|
||||||
|
transform.setTranslation(position);
|
||||||
|
batch.setModelTransform(transform);
|
||||||
|
eyeDiameter = geometry->getFBXGeometry().rightEyeSize;
|
||||||
|
if (eyeDiameter == 0.0f) {
|
||||||
|
eyeDiameter = DEFAULT_EYE_DIAMETER;
|
||||||
|
}
|
||||||
|
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch,
|
||||||
|
eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT, 15, 15, glm::vec4(LOOKING_AT_ME_COLOR, alpha));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// quick check before falling into the code below:
|
// quick check before falling into the code below:
|
||||||
|
|
|
@ -55,6 +55,8 @@ Head::Head(Avatar* owningAvatar) :
|
||||||
_deltaLeanForward(0.0f),
|
_deltaLeanForward(0.0f),
|
||||||
_isCameraMoving(false),
|
_isCameraMoving(false),
|
||||||
_isLookingAtMe(false),
|
_isLookingAtMe(false),
|
||||||
|
_lookingAtMeStarted(0),
|
||||||
|
_wasLastLookingAtMe(0),
|
||||||
_faceModel(this),
|
_faceModel(this),
|
||||||
_leftEyeLookAtID(DependencyManager::get<GeometryCache>()->allocateID()),
|
_leftEyeLookAtID(DependencyManager::get<GeometryCache>()->allocateID()),
|
||||||
_rightEyeLookAtID(DependencyManager::get<GeometryCache>()->allocateID())
|
_rightEyeLookAtID(DependencyManager::get<GeometryCache>()->allocateID())
|
||||||
|
@ -316,7 +318,7 @@ glm::quat Head::getFinalOrientationInLocalFrame() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Head::getCorrectedLookAtPosition() {
|
glm::vec3 Head::getCorrectedLookAtPosition() {
|
||||||
if (_isLookingAtMe) {
|
if (isLookingAtMe()) {
|
||||||
return _correctedLookAtPosition;
|
return _correctedLookAtPosition;
|
||||||
} else {
|
} else {
|
||||||
return getLookAtPosition();
|
return getLookAtPosition();
|
||||||
|
@ -324,10 +326,21 @@ glm::vec3 Head::getCorrectedLookAtPosition() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition) {
|
void Head::setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition) {
|
||||||
|
if (!isLookingAtMe()) {
|
||||||
|
_lookingAtMeStarted = usecTimestampNow();
|
||||||
|
}
|
||||||
_isLookingAtMe = true;
|
_isLookingAtMe = true;
|
||||||
|
_wasLastLookingAtMe = usecTimestampNow();
|
||||||
_correctedLookAtPosition = correctedLookAtPosition;
|
_correctedLookAtPosition = correctedLookAtPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Head::isLookingAtMe() {
|
||||||
|
// Allow for outages such as may be encountered during avatar movement
|
||||||
|
quint64 now = usecTimestampNow();
|
||||||
|
const quint64 LOOKING_AT_ME_GAP_ALLOWED = 1000000; // microseconds
|
||||||
|
return _isLookingAtMe || (now - _wasLastLookingAtMe) < LOOKING_AT_ME_GAP_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
glm::quat Head::getCameraOrientation() const {
|
glm::quat Head::getCameraOrientation() const {
|
||||||
// NOTE: Head::getCameraOrientation() is not used for orienting the camera "view" while in Oculus mode, so
|
// NOTE: Head::getCameraOrientation() is not used for orienting the camera "view" while in Oculus mode, so
|
||||||
// you may wonder why this code is here. This method will be called while in Oculus mode to determine how
|
// you may wonder why this code is here. This method will be called while in Oculus mode to determine how
|
||||||
|
|
|
@ -52,8 +52,9 @@ public:
|
||||||
void setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition);
|
void setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition);
|
||||||
glm::vec3 getCorrectedLookAtPosition();
|
glm::vec3 getCorrectedLookAtPosition();
|
||||||
void clearCorrectedLookAtPosition() { _isLookingAtMe = false; }
|
void clearCorrectedLookAtPosition() { _isLookingAtMe = false; }
|
||||||
bool getIsLookingAtMe() { return _isLookingAtMe; }
|
bool isLookingAtMe();
|
||||||
|
quint64 getLookingAtMeStarted() { return _lookingAtMeStarted; }
|
||||||
|
|
||||||
float getScale() const { return _scale; }
|
float getScale() const { return _scale; }
|
||||||
glm::vec3 getPosition() const { return _position; }
|
glm::vec3 getPosition() const { return _position; }
|
||||||
const glm::vec3& getEyePosition() const { return _eyePosition; }
|
const glm::vec3& getEyePosition() const { return _eyePosition; }
|
||||||
|
@ -139,6 +140,8 @@ private:
|
||||||
|
|
||||||
bool _isCameraMoving;
|
bool _isCameraMoving;
|
||||||
bool _isLookingAtMe;
|
bool _isLookingAtMe;
|
||||||
|
quint64 _lookingAtMeStarted;
|
||||||
|
quint64 _wasLastLookingAtMe;
|
||||||
FaceModel _faceModel;
|
FaceModel _faceModel;
|
||||||
|
|
||||||
glm::vec3 _correctedLookAtPosition;
|
glm::vec3 _correctedLookAtPosition;
|
||||||
|
|
|
@ -1290,7 +1290,6 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
||||||
|
|
||||||
void MyAvatar::updateOrientation(float deltaTime) {
|
void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
// Smoothly rotate body with arrow keys
|
// Smoothly rotate body with arrow keys
|
||||||
float driveLeft = _driveKeys[ROT_LEFT] - _driveKeys[ROT_RIGHT];
|
|
||||||
float targetSpeed = (_driveKeys[ROT_LEFT] - _driveKeys[ROT_RIGHT]) * YAW_SPEED;
|
float targetSpeed = (_driveKeys[ROT_LEFT] - _driveKeys[ROT_RIGHT]) * YAW_SPEED;
|
||||||
if (targetSpeed != 0.0f) {
|
if (targetSpeed != 0.0f) {
|
||||||
const float ROTATION_RAMP_TIMESCALE = 0.1f;
|
const float ROTATION_RAMP_TIMESCALE = 0.1f;
|
||||||
|
@ -1551,6 +1550,9 @@ void MyAvatar::maybeUpdateBillboard() {
|
||||||
QBuffer buffer(&_billboard);
|
QBuffer buffer(&_billboard);
|
||||||
buffer.open(QIODevice::WriteOnly);
|
buffer.open(QIODevice::WriteOnly);
|
||||||
image.save(&buffer, "PNG");
|
image.save(&buffer, "PNG");
|
||||||
|
#ifdef DEBUG
|
||||||
|
image.save("billboard.png", "PNG");
|
||||||
|
#endif
|
||||||
_billboardValid = true;
|
_billboardValid = true;
|
||||||
|
|
||||||
sendBillboardPacket();
|
sendBillboardPacket();
|
||||||
|
|
|
@ -91,13 +91,12 @@ private:
|
||||||
|
|
||||||
int _leftBlinkIndex;
|
int _leftBlinkIndex;
|
||||||
int _rightBlinkIndex;
|
int _rightBlinkIndex;
|
||||||
int _leftEyeOpenIndex;
|
|
||||||
int _rightEyeOpenIndex;
|
|
||||||
|
|
||||||
int _leftEyeDownIndex;
|
int _leftEyeDownIndex;
|
||||||
int _rightEyeDownIndex;
|
int _rightEyeDownIndex;
|
||||||
int _leftEyeInIndex;
|
int _leftEyeInIndex;
|
||||||
int _rightEyeInIndex;
|
int _rightEyeInIndex;
|
||||||
|
int _leftEyeOpenIndex;
|
||||||
|
int _rightEyeOpenIndex;
|
||||||
|
|
||||||
int _browDownLeftIndex;
|
int _browDownLeftIndex;
|
||||||
int _browDownRightIndex;
|
int _browDownRightIndex;
|
||||||
|
|
|
@ -520,8 +520,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||||
triggerButton = Qt::LeftButton;
|
triggerButton = Qt::LeftButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)
|
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
||||||
|| Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
|
||||||
pos = qApp->getApplicationCompositor().getPalmClickLocation(palm);
|
pos = qApp->getApplicationCompositor().getPalmClickLocation(palm);
|
||||||
} else {
|
} else {
|
||||||
// Get directon relative to avatar orientation
|
// Get directon relative to avatar orientation
|
||||||
|
|
|
@ -57,7 +57,7 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid
|
||||||
} else {
|
} else {
|
||||||
auto dialogWidget = new QDialog(Application::getInstance()->getWindow(), Qt::Window);
|
auto dialogWidget = new QDialog(Application::getInstance()->getWindow(), Qt::Window);
|
||||||
dialogWidget->setWindowTitle(title);
|
dialogWidget->setWindowTitle(title);
|
||||||
dialogWidget->setMinimumSize(width, height);
|
dialogWidget->resize(width, height);
|
||||||
connect(dialogWidget, &QDialog::finished, this, &WebWindowClass::hasClosed);
|
connect(dialogWidget, &QDialog::finished, this, &WebWindowClass::hasClosed);
|
||||||
|
|
||||||
auto layout = new QVBoxLayout(dialogWidget);
|
auto layout = new QVBoxLayout(dialogWidget);
|
||||||
|
@ -142,3 +142,7 @@ QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine*
|
||||||
|
|
||||||
return engine->newQObject(retVal);
|
return engine->newQObject(retVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebWindowClass::setTitle(const QString& title) {
|
||||||
|
_windowWidget->setWindowTitle(title);
|
||||||
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ public slots:
|
||||||
void raise();
|
void raise();
|
||||||
ScriptEventBridge* getEventBridge() const { return _eventBridge; }
|
ScriptEventBridge* getEventBridge() const { return _eventBridge; }
|
||||||
void addEventBridgeToWindowObject();
|
void addEventBridgeToWindowObject();
|
||||||
|
void setTitle(const QString& title);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void closed();
|
void closed();
|
||||||
|
|
|
@ -491,24 +491,18 @@ void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) {
|
||||||
|
|
||||||
auto canvasSize = qApp->getCanvasSize();
|
auto canvasSize = qApp->getCanvasSize();
|
||||||
int mouseX, mouseY;
|
int mouseX, mouseY;
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
|
// Get directon relative to avatar orientation
|
||||||
QPoint res = getPalmClickLocation(palmData);
|
glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection();
|
||||||
mouseX = res.x();
|
|
||||||
mouseY = res.y();
|
|
||||||
} else {
|
|
||||||
// Get directon relative to avatar orientation
|
|
||||||
glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection();
|
|
||||||
|
|
||||||
// Get the angles, scaled between (-0.5,0.5)
|
// Get the angles, scaled between (-0.5,0.5)
|
||||||
float xAngle = (atan2(direction.z, direction.x) + PI_OVER_TWO);
|
float xAngle = (atan2f(direction.z, direction.x) + PI_OVER_TWO);
|
||||||
float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)PI_OVER_TWO));
|
float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)PI_OVER_TWO));
|
||||||
|
|
||||||
// Get the pixel range over which the xAngle and yAngle are scaled
|
// Get the pixel range over which the xAngle and yAngle are scaled
|
||||||
float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult();
|
float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult();
|
||||||
|
|
||||||
mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle);
|
mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle);
|
||||||
mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle);
|
mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle);
|
||||||
}
|
|
||||||
|
|
||||||
//If the cursor is out of the screen then don't render it
|
//If the cursor is out of the screen then don't render it
|
||||||
if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) {
|
if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <gpu/GLBackend.h>
|
#include <gpu/GLBackend.h>
|
||||||
#include <gpu/GLBackendShared.h>
|
#include <gpu/GLBackendShared.h>
|
||||||
|
#include <FramebufferCache.h>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <OffscreenUi.h>
|
#include <OffscreenUi.h>
|
||||||
#include <CursorManager.h>
|
#include <CursorManager.h>
|
||||||
|
@ -93,6 +94,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
||||||
// Now render the overlay components together into a single texture
|
// Now render the overlay components together into a single texture
|
||||||
renderDomainConnectionStatusBorder(renderArgs); // renders the connected domain line
|
renderDomainConnectionStatusBorder(renderArgs); // renders the connected domain line
|
||||||
renderAudioScope(renderArgs); // audio scope in the very back
|
renderAudioScope(renderArgs); // audio scope in the very back
|
||||||
|
renderRearView(renderArgs); // renders the mirror view selfie
|
||||||
renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture, and the text overlays from scripts
|
renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture, and the text overlays from scripts
|
||||||
renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope
|
renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope
|
||||||
renderStatsAndLogs(renderArgs); // currently renders nothing
|
renderStatsAndLogs(renderArgs); // currently renders nothing
|
||||||
|
@ -167,6 +169,39 @@ void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
|
void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||||
|
gpu::Batch& batch = *renderArgs->_batch;
|
||||||
|
|
||||||
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
|
|
||||||
|
auto framebuffer = DependencyManager::get<FramebufferCache>();
|
||||||
|
auto selfieTexture = framebuffer->getSelfieFramebuffer()->getRenderBuffer(0);
|
||||||
|
|
||||||
|
int width = renderArgs->_viewport.z;
|
||||||
|
int height = renderArgs->_viewport.w;
|
||||||
|
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP);
|
||||||
|
batch.setProjectionTransform(legacyProjection);
|
||||||
|
batch.setModelTransform(Transform());
|
||||||
|
batch.setViewTransform(Transform());
|
||||||
|
|
||||||
|
float screenRatio = ((float)qApp->getDevicePixelRatio());
|
||||||
|
float renderRatio = ((float)screenRatio * qApp->getRenderResolutionScale());
|
||||||
|
|
||||||
|
auto viewport = qApp->getMirrorViewRect();
|
||||||
|
glm::vec2 bottomLeft(viewport.left(), viewport.top() + viewport.height());
|
||||||
|
glm::vec2 topRight(viewport.left() + viewport.width(), viewport.top());
|
||||||
|
bottomLeft *= screenRatio;
|
||||||
|
topRight *= screenRatio;
|
||||||
|
glm::vec2 texCoordMinCorner(0.0f, 0.0f);
|
||||||
|
glm::vec2 texCoordMaxCorner(viewport.width() * renderRatio / float(selfieTexture->getWidth()), viewport.height() * renderRatio / float(selfieTexture->getHeight()));
|
||||||
|
|
||||||
|
geometryCache->useSimpleDrawPipeline(batch, true);
|
||||||
|
batch.setResourceTexture(0, selfieTexture);
|
||||||
|
geometryCache->renderQuad(batch, bottomLeft, topRight, texCoordMinCorner, texCoordMaxCorner, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
|
batch.setResourceTexture(0, renderArgs->_whiteTexture);
|
||||||
|
geometryCache->useSimpleDrawPipeline(batch, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
|
void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
|
||||||
|
|
|
@ -125,8 +125,10 @@ void AudioStatsDialog::renderStats() {
|
||||||
audioInputBufferLatency = (double)_stats->getAudioInputMsecsReadStats().getWindowAverage();
|
audioInputBufferLatency = (double)_stats->getAudioInputMsecsReadStats().getWindowAverage();
|
||||||
inputRingBufferLatency = (double)_stats->getInputRungBufferMsecsAvailableStats().getWindowAverage();
|
inputRingBufferLatency = (double)_stats->getInputRungBufferMsecsAvailableStats().getWindowAverage();
|
||||||
networkRoundtripLatency = (double) audioMixerNodePointer->getPingMs();
|
networkRoundtripLatency = (double) audioMixerNodePointer->getPingMs();
|
||||||
mixerRingBufferLatency = (double)_stats->getMixerAvatarStreamStats()._framesAvailableAverage * AudioConstants::NETWORK_FRAME_MSECS;
|
mixerRingBufferLatency = (double)_stats->getMixerAvatarStreamStats()._framesAvailableAverage *
|
||||||
outputRingBufferLatency = (double)downstreamAudioStreamStats._framesAvailableAverage * AudioConstants::NETWORK_FRAME_MSECS;
|
(double)AudioConstants::NETWORK_FRAME_MSECS;
|
||||||
|
outputRingBufferLatency = (double)downstreamAudioStreamStats._framesAvailableAverage *
|
||||||
|
(double)AudioConstants::NETWORK_FRAME_MSECS;
|
||||||
audioOutputBufferLatency = (double)_stats->getAudioOutputMsecsUnplayedStats().getWindowAverage();
|
audioOutputBufferLatency = (double)_stats->getAudioOutputMsecsUnplayedStats().getWindowAverage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
||||||
|
|
||||||
// TODO: handle registration point??
|
// TODO: handle registration point??
|
||||||
glm::vec3 position = getPosition();
|
glm::vec3 position = getPosition();
|
||||||
glm::vec3 center = getCenter();
|
|
||||||
glm::vec3 dimensions = getDimensions();
|
glm::vec3 dimensions = getDimensions();
|
||||||
glm::quat rotation = getRotation();
|
glm::quat rotation = getRotation();
|
||||||
|
|
||||||
|
|
|
@ -2616,10 +2616,17 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
||||||
buildModelMesh(extracted);
|
buildModelMesh(extracted);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
if (extracted.mesh.isEye) {
|
||||||
|
if (maxJointIndex == geometry.leftEyeJointIndex) {
|
||||||
|
geometry.leftEyeSize = extracted.mesh.meshExtents.largestDimension() * offsetScale;
|
||||||
|
} else {
|
||||||
|
geometry.rightEyeSize = extracted.mesh.meshExtents.largestDimension() * offsetScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
geometry.meshes.append(extracted.mesh);
|
geometry.meshes.append(extracted.mesh);
|
||||||
int meshIndex = geometry.meshes.size() - 1;
|
int meshIndex = geometry.meshes.size() - 1;
|
||||||
meshIDsToMeshIndices.insert(it.key(), meshIndex);
|
meshIDsToMeshIndices.insert(it.key(), meshIndex);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// now that all joints have been scanned, compute a collision shape for each joint
|
// now that all joints have been scanned, compute a collision shape for each joint
|
||||||
|
|
|
@ -232,7 +232,10 @@ public:
|
||||||
int rightHandJointIndex = -1;
|
int rightHandJointIndex = -1;
|
||||||
int leftToeJointIndex = -1;
|
int leftToeJointIndex = -1;
|
||||||
int rightToeJointIndex = -1;
|
int rightToeJointIndex = -1;
|
||||||
|
|
||||||
|
float leftEyeSize = 0.0f; // Maximum mesh extents dimension
|
||||||
|
float rightEyeSize = 0.0f;
|
||||||
|
|
||||||
QVector<int> humanIKJointIndices;
|
QVector<int> humanIKJointIndices;
|
||||||
|
|
||||||
glm::vec3 palmDirection;
|
glm::vec3 palmDirection;
|
||||||
|
|
|
@ -106,36 +106,6 @@ void Batch::drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, ui
|
||||||
_params.push_back(nbInstances);
|
_params.push_back(nbInstances);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::clearFramebuffer(Framebuffer::Masks targets, const Vec4& color, float depth, int stencil, bool enableScissor) {
|
|
||||||
ADD_COMMAND(clearFramebuffer);
|
|
||||||
|
|
||||||
_params.push_back(enableScissor);
|
|
||||||
_params.push_back(stencil);
|
|
||||||
_params.push_back(depth);
|
|
||||||
_params.push_back(color.w);
|
|
||||||
_params.push_back(color.z);
|
|
||||||
_params.push_back(color.y);
|
|
||||||
_params.push_back(color.x);
|
|
||||||
_params.push_back(targets);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Batch::clearColorFramebuffer(Framebuffer::Masks targets, const Vec4& color, bool enableScissor) {
|
|
||||||
clearFramebuffer(targets & Framebuffer::BUFFER_COLORS, color, 1.0f, 0, enableScissor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Batch::clearDepthFramebuffer(float depth, bool enableScissor) {
|
|
||||||
clearFramebuffer(Framebuffer::BUFFER_DEPTH, Vec4(0.0f), depth, 0, enableScissor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Batch::clearStencilFramebuffer(int stencil, bool enableScissor) {
|
|
||||||
clearFramebuffer(Framebuffer::BUFFER_STENCIL, Vec4(0.0f), 1.0f, stencil, enableScissor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Batch::clearDepthStencilFramebuffer(float depth, int stencil, bool enableScissor) {
|
|
||||||
clearFramebuffer(Framebuffer::BUFFER_DEPTHSTENCIL, Vec4(0.0f), depth, stencil, enableScissor);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Batch::setInputFormat(const Stream::FormatPointer& format) {
|
void Batch::setInputFormat(const Stream::FormatPointer& format) {
|
||||||
ADD_COMMAND(setInputFormat);
|
ADD_COMMAND(setInputFormat);
|
||||||
|
|
||||||
|
@ -220,10 +190,7 @@ void Batch::setStateBlendFactor(const Vec4& factor) {
|
||||||
void Batch::setStateScissorRect(const Vec4i& rect) {
|
void Batch::setStateScissorRect(const Vec4i& rect) {
|
||||||
ADD_COMMAND(setStateScissorRect);
|
ADD_COMMAND(setStateScissorRect);
|
||||||
|
|
||||||
_params.push_back(rect.x);
|
_params.push_back(cacheData(sizeof(Vec4i), &rect));
|
||||||
_params.push_back(rect.y);
|
|
||||||
_params.push_back(rect.z);
|
|
||||||
_params.push_back(rect.w);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size) {
|
void Batch::setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size) {
|
||||||
|
@ -258,6 +225,35 @@ void Batch::setFramebuffer(const FramebufferPointer& framebuffer) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Batch::clearFramebuffer(Framebuffer::Masks targets, const Vec4& color, float depth, int stencil, bool enableScissor) {
|
||||||
|
ADD_COMMAND(clearFramebuffer);
|
||||||
|
|
||||||
|
_params.push_back(enableScissor);
|
||||||
|
_params.push_back(stencil);
|
||||||
|
_params.push_back(depth);
|
||||||
|
_params.push_back(color.w);
|
||||||
|
_params.push_back(color.z);
|
||||||
|
_params.push_back(color.y);
|
||||||
|
_params.push_back(color.x);
|
||||||
|
_params.push_back(targets);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Batch::clearColorFramebuffer(Framebuffer::Masks targets, const Vec4& color, bool enableScissor) {
|
||||||
|
clearFramebuffer(targets & Framebuffer::BUFFER_COLORS, color, 1.0f, 0, enableScissor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Batch::clearDepthFramebuffer(float depth, bool enableScissor) {
|
||||||
|
clearFramebuffer(Framebuffer::BUFFER_DEPTH, Vec4(0.0f), depth, 0, enableScissor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Batch::clearStencilFramebuffer(int stencil, bool enableScissor) {
|
||||||
|
clearFramebuffer(Framebuffer::BUFFER_STENCIL, Vec4(0.0f), 1.0f, stencil, enableScissor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Batch::clearDepthStencilFramebuffer(float depth, int stencil, bool enableScissor) {
|
||||||
|
clearFramebuffer(Framebuffer::BUFFER_DEPTHSTENCIL, Vec4(0.0f), depth, stencil, enableScissor);
|
||||||
|
}
|
||||||
|
|
||||||
void Batch::blit(const FramebufferPointer& src, const Vec4i& srcViewport,
|
void Batch::blit(const FramebufferPointer& src, const Vec4i& srcViewport,
|
||||||
const FramebufferPointer& dst, const Vec4i& dstViewport) {
|
const FramebufferPointer& dst, const Vec4i& dstViewport) {
|
||||||
ADD_COMMAND(blit);
|
ADD_COMMAND(blit);
|
||||||
|
|
|
@ -54,15 +54,6 @@ public:
|
||||||
void drawInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbVertices, uint32 startVertex = 0, uint32 startInstance = 0);
|
void drawInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbVertices, uint32 startVertex = 0, uint32 startInstance = 0);
|
||||||
void drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0, uint32 startInstance = 0);
|
void drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0, uint32 startInstance = 0);
|
||||||
|
|
||||||
// Clear framebuffer layers
|
|
||||||
// Targets can be any of the render buffers contained in the Framebuffer
|
|
||||||
// Optionally the scissor test can be enabled locally for this command and to restrict the clearing command to the pixels contained in the scissor rectangle
|
|
||||||
void clearFramebuffer(Framebuffer::Masks targets, const Vec4& color, float depth, int stencil, bool enableScissor = false);
|
|
||||||
void clearColorFramebuffer(Framebuffer::Masks targets, const Vec4& color, bool enableScissor = false); // not a command, just a shortcut for clearFramebuffer, mask out targets to make sure it touches only color targets
|
|
||||||
void clearDepthFramebuffer(float depth, bool enableScissor = false); // not a command, just a shortcut for clearFramebuffer, it touches only depth target
|
|
||||||
void clearStencilFramebuffer(int stencil, bool enableScissor = false); // not a command, just a shortcut for clearFramebuffer, it touches only stencil target
|
|
||||||
void clearDepthStencilFramebuffer(float depth, int stencil, bool enableScissor = false); // not a command, just a shortcut for clearFramebuffer, it touches depth and stencil target
|
|
||||||
|
|
||||||
// Input Stage
|
// Input Stage
|
||||||
// InputFormat
|
// InputFormat
|
||||||
// InputBuffers
|
// InputBuffers
|
||||||
|
@ -105,9 +96,17 @@ public:
|
||||||
|
|
||||||
// Framebuffer Stage
|
// Framebuffer Stage
|
||||||
void setFramebuffer(const FramebufferPointer& framebuffer);
|
void setFramebuffer(const FramebufferPointer& framebuffer);
|
||||||
void blit(const FramebufferPointer& src, const Vec4i& srcViewport,
|
|
||||||
const FramebufferPointer& dst, const Vec4i& dstViewport);
|
// Clear framebuffer layers
|
||||||
|
// Targets can be any of the render buffers contained in the currnetly bound Framebuffer
|
||||||
|
// Optionally the scissor test can be enabled locally for this command and to restrict the clearing command to the pixels contained in the scissor rectangle
|
||||||
|
void clearFramebuffer(Framebuffer::Masks targets, const Vec4& color, float depth, int stencil, bool enableScissor = false);
|
||||||
|
void clearColorFramebuffer(Framebuffer::Masks targets, const Vec4& color, bool enableScissor = false); // not a command, just a shortcut for clearFramebuffer, mask out targets to make sure it touches only color targets
|
||||||
|
void clearDepthFramebuffer(float depth, bool enableScissor = false); // not a command, just a shortcut for clearFramebuffer, it touches only depth target
|
||||||
|
void clearStencilFramebuffer(int stencil, bool enableScissor = false); // not a command, just a shortcut for clearFramebuffer, it touches only stencil target
|
||||||
|
void clearDepthStencilFramebuffer(float depth, int stencil, bool enableScissor = false); // not a command, just a shortcut for clearFramebuffer, it touches depth and stencil target
|
||||||
|
|
||||||
|
void blit(const FramebufferPointer& src, const Vec4i& srcViewport, const FramebufferPointer& dst, const Vec4i& dstViewport);
|
||||||
|
|
||||||
// Query Section
|
// Query Section
|
||||||
void beginQuery(const QueryPointer& query);
|
void beginQuery(const QueryPointer& query);
|
||||||
|
@ -163,8 +162,6 @@ public:
|
||||||
COMMAND_drawInstanced,
|
COMMAND_drawInstanced,
|
||||||
COMMAND_drawIndexedInstanced,
|
COMMAND_drawIndexedInstanced,
|
||||||
|
|
||||||
COMMAND_clearFramebuffer,
|
|
||||||
|
|
||||||
COMMAND_setInputFormat,
|
COMMAND_setInputFormat,
|
||||||
COMMAND_setInputBuffer,
|
COMMAND_setInputBuffer,
|
||||||
COMMAND_setIndexBuffer,
|
COMMAND_setIndexBuffer,
|
||||||
|
@ -182,6 +179,7 @@ public:
|
||||||
COMMAND_setResourceTexture,
|
COMMAND_setResourceTexture,
|
||||||
|
|
||||||
COMMAND_setFramebuffer,
|
COMMAND_setFramebuffer,
|
||||||
|
COMMAND_clearFramebuffer,
|
||||||
COMMAND_blit,
|
COMMAND_blit,
|
||||||
|
|
||||||
COMMAND_beginQuery,
|
COMMAND_beginQuery,
|
||||||
|
|
|
@ -40,4 +40,8 @@ void Context::render(Batch& batch) {
|
||||||
void Context::syncCache() {
|
void Context::syncCache() {
|
||||||
PROFILE_RANGE(__FUNCTION__);
|
PROFILE_RANGE(__FUNCTION__);
|
||||||
_backend->syncCache();
|
_backend->syncCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) {
|
||||||
|
_backend->downloadFramebuffer(srcFramebuffer, region, destImage);
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include "Pipeline.h"
|
#include "Pipeline.h"
|
||||||
#include "Framebuffer.h"
|
#include "Framebuffer.h"
|
||||||
|
|
||||||
|
class QImage;
|
||||||
|
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
class Backend {
|
class Backend {
|
||||||
|
@ -28,6 +30,8 @@ public:
|
||||||
virtual~ Backend() {};
|
virtual~ Backend() {};
|
||||||
virtual void render(Batch& batch) = 0;
|
virtual void render(Batch& batch) = 0;
|
||||||
virtual void syncCache() = 0;
|
virtual void syncCache() = 0;
|
||||||
|
virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0;
|
||||||
|
|
||||||
|
|
||||||
class TransformObject {
|
class TransformObject {
|
||||||
public:
|
public:
|
||||||
|
@ -121,6 +125,10 @@ public:
|
||||||
|
|
||||||
void syncCache();
|
void syncCache();
|
||||||
|
|
||||||
|
// Downloading the Framebuffer is a synchronous action that is not efficient.
|
||||||
|
// It s here for convenience to easily capture a snapshot
|
||||||
|
void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Context(const Context& context);
|
Context(const Context& context);
|
||||||
|
|
||||||
|
|
22
libraries/gpu/src/gpu/DrawTextureOpaque.slf
Executable file
22
libraries/gpu/src/gpu/DrawTextureOpaque.slf
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// Draw texture 0 fetched at texcoord.xy
|
||||||
|
// Alpha is 1
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 6/22/2015
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
uniform sampler2D colorMap;
|
||||||
|
|
||||||
|
varying vec2 varTexcoord;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
gl_FragColor = vec4(texture2D(colorMap, varTexcoord).xyz, 1.0);
|
||||||
|
}
|
|
@ -14,8 +14,6 @@
|
||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class QImage;
|
|
||||||
|
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
typedef Element Format;
|
typedef Element Format;
|
||||||
|
@ -134,8 +132,6 @@ public:
|
||||||
static const uint32 MAX_NUM_RENDER_BUFFERS = 8;
|
static const uint32 MAX_NUM_RENDER_BUFFERS = 8;
|
||||||
static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; }
|
static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; }
|
||||||
|
|
||||||
void getImage(QImage* result) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SwapchainPointer _swapchain;
|
SwapchainPointer _swapchain;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
||||||
(&::gpu::GLBackend::do_drawIndexed),
|
(&::gpu::GLBackend::do_drawIndexed),
|
||||||
(&::gpu::GLBackend::do_drawInstanced),
|
(&::gpu::GLBackend::do_drawInstanced),
|
||||||
(&::gpu::GLBackend::do_drawIndexedInstanced),
|
(&::gpu::GLBackend::do_drawIndexedInstanced),
|
||||||
(&::gpu::GLBackend::do_clearFramebuffer),
|
|
||||||
|
|
||||||
(&::gpu::GLBackend::do_setInputFormat),
|
(&::gpu::GLBackend::do_setInputFormat),
|
||||||
(&::gpu::GLBackend::do_setInputBuffer),
|
(&::gpu::GLBackend::do_setInputBuffer),
|
||||||
|
@ -40,6 +39,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
||||||
(&::gpu::GLBackend::do_setResourceTexture),
|
(&::gpu::GLBackend::do_setResourceTexture),
|
||||||
|
|
||||||
(&::gpu::GLBackend::do_setFramebuffer),
|
(&::gpu::GLBackend::do_setFramebuffer),
|
||||||
|
(&::gpu::GLBackend::do_clearFramebuffer),
|
||||||
(&::gpu::GLBackend::do_blit),
|
(&::gpu::GLBackend::do_blit),
|
||||||
|
|
||||||
(&::gpu::GLBackend::do_beginQuery),
|
(&::gpu::GLBackend::do_beginQuery),
|
||||||
|
@ -192,6 +192,7 @@ void GLBackend::syncCache() {
|
||||||
syncTransformStateCache();
|
syncTransformStateCache();
|
||||||
syncPipelineStateCache();
|
syncPipelineStateCache();
|
||||||
syncInputStateCache();
|
syncInputStateCache();
|
||||||
|
syncOutputStateCache();
|
||||||
|
|
||||||
glEnable(GL_LINE_SMOOTH);
|
glEnable(GL_LINE_SMOOTH);
|
||||||
}
|
}
|
||||||
|
@ -245,68 +246,6 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) {
|
||||||
(void) CHECK_GL_ERROR();
|
(void) CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) {
|
|
||||||
|
|
||||||
uint32 masks = batch._params[paramOffset + 7]._uint;
|
|
||||||
Vec4 color;
|
|
||||||
color.x = batch._params[paramOffset + 6]._float;
|
|
||||||
color.y = batch._params[paramOffset + 5]._float;
|
|
||||||
color.z = batch._params[paramOffset + 4]._float;
|
|
||||||
color.w = batch._params[paramOffset + 3]._float;
|
|
||||||
float depth = batch._params[paramOffset + 2]._float;
|
|
||||||
int stencil = batch._params[paramOffset + 1]._int;
|
|
||||||
int useScissor = batch._params[paramOffset + 0]._int;
|
|
||||||
|
|
||||||
GLuint glmask = 0;
|
|
||||||
if (masks & Framebuffer::BUFFER_STENCIL) {
|
|
||||||
glClearStencil(stencil);
|
|
||||||
glmask |= GL_STENCIL_BUFFER_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (masks & Framebuffer::BUFFER_DEPTH) {
|
|
||||||
glClearDepth(depth);
|
|
||||||
glmask |= GL_DEPTH_BUFFER_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<GLenum> drawBuffers;
|
|
||||||
if (masks & Framebuffer::BUFFER_COLORS) {
|
|
||||||
for (unsigned int i = 0; i < Framebuffer::MAX_NUM_RENDER_BUFFERS; i++) {
|
|
||||||
if (masks & (1 << i)) {
|
|
||||||
drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!drawBuffers.empty()) {
|
|
||||||
glDrawBuffers(drawBuffers.size(), drawBuffers.data());
|
|
||||||
glClearColor(color.x, color.y, color.z, color.w);
|
|
||||||
glmask |= GL_COLOR_BUFFER_BIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply scissor if needed and if not already on
|
|
||||||
bool doEnableScissor = (useScissor && (!_pipeline._stateCache.scissorEnable));
|
|
||||||
if (doEnableScissor) {
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
glClear(glmask);
|
|
||||||
|
|
||||||
// Restore scissor if needed
|
|
||||||
if (doEnableScissor) {
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the color draw buffers only if a frmaebuffer is bound
|
|
||||||
if (_output._framebuffer && !drawBuffers.empty()) {
|
|
||||||
auto glFramebuffer = syncGPUObject(*_output._framebuffer);
|
|
||||||
if (glFramebuffer) {
|
|
||||||
glDrawBuffers(glFramebuffer->_colorBuffers.size(), glFramebuffer->_colorBuffers.data());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) CHECK_GL_ERROR();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: As long as we have gl calls explicitely issued from interface
|
// TODO: As long as we have gl calls explicitely issued from interface
|
||||||
// code, we need to be able to record and batch these calls. THe long
|
// code, we need to be able to record and batch these calls. THe long
|
||||||
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
||||||
|
|
|
@ -38,6 +38,10 @@ public:
|
||||||
// Let's try to avoid to do that as much as possible!
|
// Let's try to avoid to do that as much as possible!
|
||||||
virtual void syncCache();
|
virtual void syncCache();
|
||||||
|
|
||||||
|
// This is the ugly "download the pixels to sysmem for taking a snapshot"
|
||||||
|
// Just avoid using it, it's ugly and will break performances
|
||||||
|
virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage);
|
||||||
|
|
||||||
static bool checkGLError(const char* name = nullptr);
|
static bool checkGLError(const char* name = nullptr);
|
||||||
|
|
||||||
// Only checks in debug builds
|
// Only checks in debug builds
|
||||||
|
@ -237,8 +241,6 @@ protected:
|
||||||
void do_drawInstanced(Batch& batch, uint32 paramOffset);
|
void do_drawInstanced(Batch& batch, uint32 paramOffset);
|
||||||
void do_drawIndexedInstanced(Batch& batch, uint32 paramOffset);
|
void do_drawIndexedInstanced(Batch& batch, uint32 paramOffset);
|
||||||
|
|
||||||
void do_clearFramebuffer(Batch& batch, uint32 paramOffset);
|
|
||||||
|
|
||||||
// Input Stage
|
// Input Stage
|
||||||
void do_setInputFormat(Batch& batch, uint32 paramOffset);
|
void do_setInputFormat(Batch& batch, uint32 paramOffset);
|
||||||
void do_setInputBuffer(Batch& batch, uint32 paramOffset);
|
void do_setInputBuffer(Batch& batch, uint32 paramOffset);
|
||||||
|
@ -381,13 +383,17 @@ protected:
|
||||||
|
|
||||||
// Output stage
|
// Output stage
|
||||||
void do_setFramebuffer(Batch& batch, uint32 paramOffset);
|
void do_setFramebuffer(Batch& batch, uint32 paramOffset);
|
||||||
|
void do_clearFramebuffer(Batch& batch, uint32 paramOffset);
|
||||||
void do_blit(Batch& batch, uint32 paramOffset);
|
void do_blit(Batch& batch, uint32 paramOffset);
|
||||||
|
|
||||||
|
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
||||||
|
void syncOutputStateCache();
|
||||||
|
|
||||||
struct OutputStageState {
|
struct OutputStageState {
|
||||||
|
|
||||||
FramebufferPointer _framebuffer = nullptr;
|
FramebufferPointer _framebuffer = nullptr;
|
||||||
|
GLuint _drawFBO = 0;
|
||||||
|
|
||||||
OutputStageState() {}
|
OutputStageState() {}
|
||||||
} _output;
|
} _output;
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,12 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
#include <qimage.h>
|
||||||
|
|
||||||
#include "GPULogging.h"
|
#include "GPULogging.h"
|
||||||
#include "GLBackendShared.h"
|
#include "GLBackendShared.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
|
|
||||||
GLBackend::GLFramebuffer::GLFramebuffer() {}
|
GLBackend::GLFramebuffer::GLFramebuffer() {}
|
||||||
|
@ -34,6 +37,9 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
|
||||||
|
|
||||||
// need to have a gpu object?
|
// need to have a gpu object?
|
||||||
if (!object) {
|
if (!object) {
|
||||||
|
GLint currentFBO;
|
||||||
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFBO);
|
||||||
|
|
||||||
GLuint fbo;
|
GLuint fbo;
|
||||||
glGenFramebuffers(1, &fbo);
|
glGenFramebuffers(1, &fbo);
|
||||||
(void) CHECK_GL_ERROR();
|
(void) CHECK_GL_ERROR();
|
||||||
|
@ -84,6 +90,8 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
|
||||||
(void) CHECK_GL_ERROR();
|
(void) CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,6 +147,9 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
|
||||||
object->_fbo = fbo;
|
object->_fbo = fbo;
|
||||||
object->_colorBuffers = colorBuffers;
|
object->_colorBuffers = colorBuffers;
|
||||||
Backend::setGPUObject(framebuffer, object);
|
Backend::setGPUObject(framebuffer, object);
|
||||||
|
|
||||||
|
// restore the current framebuffer
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
|
||||||
}
|
}
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
|
@ -158,15 +169,93 @@ GLuint GLBackend::getFramebufferID(const FramebufferPointer& framebuffer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLBackend::syncOutputStateCache() {
|
||||||
|
GLint currentFBO;
|
||||||
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFBO);
|
||||||
|
|
||||||
|
_output._drawFBO = currentFBO;
|
||||||
|
_output._framebuffer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) {
|
void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) {
|
||||||
auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
|
auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
|
||||||
|
|
||||||
if (_output._framebuffer != framebuffer) {
|
if (_output._framebuffer != framebuffer) {
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getFramebufferID(framebuffer));
|
auto newFBO = getFramebufferID(framebuffer);
|
||||||
|
if (_output._drawFBO != newFBO) {
|
||||||
|
_output._drawFBO = newFBO;
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, newFBO);
|
||||||
|
}
|
||||||
_output._framebuffer = framebuffer;
|
_output._framebuffer = framebuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) {
|
||||||
|
|
||||||
|
uint32 masks = batch._params[paramOffset + 7]._uint;
|
||||||
|
Vec4 color;
|
||||||
|
color.x = batch._params[paramOffset + 6]._float;
|
||||||
|
color.y = batch._params[paramOffset + 5]._float;
|
||||||
|
color.z = batch._params[paramOffset + 4]._float;
|
||||||
|
color.w = batch._params[paramOffset + 3]._float;
|
||||||
|
float depth = batch._params[paramOffset + 2]._float;
|
||||||
|
int stencil = batch._params[paramOffset + 1]._int;
|
||||||
|
int useScissor = batch._params[paramOffset + 0]._int;
|
||||||
|
|
||||||
|
GLuint glmask = 0;
|
||||||
|
if (masks & Framebuffer::BUFFER_STENCIL) {
|
||||||
|
glClearStencil(stencil);
|
||||||
|
glmask |= GL_STENCIL_BUFFER_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (masks & Framebuffer::BUFFER_DEPTH) {
|
||||||
|
glClearDepth(depth);
|
||||||
|
glmask |= GL_DEPTH_BUFFER_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<GLenum> drawBuffers;
|
||||||
|
if (masks & Framebuffer::BUFFER_COLORS) {
|
||||||
|
for (unsigned int i = 0; i < Framebuffer::MAX_NUM_RENDER_BUFFERS; i++) {
|
||||||
|
if (masks & (1 << i)) {
|
||||||
|
drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!drawBuffers.empty()) {
|
||||||
|
glDrawBuffers(drawBuffers.size(), drawBuffers.data());
|
||||||
|
glClearColor(color.x, color.y, color.z, color.w);
|
||||||
|
glmask |= GL_COLOR_BUFFER_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force the color mask cache to WRITE_ALL if not the case
|
||||||
|
do_setStateColorWriteMask(State::ColorMask::WRITE_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply scissor if needed and if not already on
|
||||||
|
bool doEnableScissor = (useScissor && (!_pipeline._stateCache.scissorEnable));
|
||||||
|
if (doEnableScissor) {
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear!
|
||||||
|
glClear(glmask);
|
||||||
|
|
||||||
|
// Restore scissor if needed
|
||||||
|
if (doEnableScissor) {
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the color draw buffers only if a frmaebuffer is bound
|
||||||
|
if (_output._framebuffer && !drawBuffers.empty()) {
|
||||||
|
auto glFramebuffer = syncGPUObject(*_output._framebuffer);
|
||||||
|
if (glFramebuffer) {
|
||||||
|
glDrawBuffers(glFramebuffer->_colorBuffers.size(), glFramebuffer->_colorBuffers.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) CHECK_GL_ERROR();
|
||||||
|
}
|
||||||
|
|
||||||
void GLBackend::do_blit(Batch& batch, uint32 paramOffset) {
|
void GLBackend::do_blit(Batch& batch, uint32 paramOffset) {
|
||||||
auto srcframebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
|
auto srcframebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
|
||||||
Vec4i srcvp;
|
Vec4i srcvp;
|
||||||
|
@ -179,9 +268,55 @@ void GLBackend::do_blit(Batch& batch, uint32 paramOffset) {
|
||||||
for (size_t i = 0; i < 4; ++i) {
|
for (size_t i = 0; i < 4; ++i) {
|
||||||
dstvp[i] = batch._params[paramOffset + 6 + i]._int;
|
dstvp[i] = batch._params[paramOffset + 6 + i]._int;
|
||||||
}
|
}
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getFramebufferID(dstframebuffer));
|
|
||||||
|
// Assign dest framebuffer if not bound already
|
||||||
|
auto newDrawFBO = getFramebufferID(dstframebuffer);
|
||||||
|
if (_output._drawFBO != newDrawFBO) {
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, newDrawFBO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// always bind the read fbo
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, getFramebufferID(srcframebuffer));
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, getFramebufferID(srcframebuffer));
|
||||||
|
|
||||||
|
// Blit!
|
||||||
glBlitFramebuffer(srcvp.x, srcvp.y, srcvp.z, srcvp.w,
|
glBlitFramebuffer(srcvp.x, srcvp.y, srcvp.z, srcvp.w,
|
||||||
dstvp.x, dstvp.y, dstvp.z, dstvp.w,
|
dstvp.x, dstvp.y, dstvp.z, dstvp.w,
|
||||||
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||||
|
|
||||||
|
// Always clean the read fbo to 0
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
// Restore draw fbo if changed
|
||||||
|
if (_output._drawFBO != newDrawFBO) {
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _output._drawFBO);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLBackend::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) {
|
||||||
|
auto readFBO = gpu::GLBackend::getFramebufferID(srcFramebuffer);
|
||||||
|
if (srcFramebuffer && readFBO) {
|
||||||
|
if ((srcFramebuffer->getWidth() < (region.x + region.z)) || (srcFramebuffer->getHeight() < (region.y + region.w))) {
|
||||||
|
qCDebug(gpulogging) << "GLBackend::downloadFramebuffer : srcFramebuffer is too small to provide the region queried";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((destImage.width() < region.z) || (destImage.height() < region.w)) {
|
||||||
|
qCDebug(gpulogging) << "GLBackend::downloadFramebuffer : destImage is too small to receive the region of the framebuffer";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLenum format = GL_BGRA;
|
||||||
|
if (destImage.format() != QImage::Format_ARGB32) {
|
||||||
|
qCDebug(gpulogging) << "GLBackend::downloadFramebuffer : destImage format must be FORMAT_ARGB32 to receive the region of the framebuffer";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(srcFramebuffer));
|
||||||
|
glReadPixels(region.x, region.y, region.z, region.w, format, GL_UNSIGNED_BYTE, destImage.bits());
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
(void) CHECK_GL_ERROR();
|
||||||
|
}
|
|
@ -757,11 +757,8 @@ void GLBackend::do_setStateBlendFactor(Batch& batch, uint32 paramOffset) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::do_setStateScissorRect(Batch& batch, uint32 paramOffset) {
|
void GLBackend::do_setStateScissorRect(Batch& batch, uint32 paramOffset) {
|
||||||
|
Vec4i rect;
|
||||||
Vec4 rect(batch._params[paramOffset + 0]._float,
|
memcpy(&rect, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i));
|
||||||
batch._params[paramOffset + 1]._float,
|
|
||||||
batch._params[paramOffset + 2]._float,
|
|
||||||
batch._params[paramOffset + 3]._float);
|
|
||||||
|
|
||||||
glScissor(rect.x, rect.y, rect.z, rect.w);
|
glScissor(rect.x, rect.y, rect.z, rect.w);
|
||||||
(void) CHECK_GL_ERROR();
|
(void) CHECK_GL_ERROR();
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "DrawTexcoordRectTransformUnitQuad_vert.h"
|
#include "DrawTexcoordRectTransformUnitQuad_vert.h"
|
||||||
#include "DrawViewportQuadTransformTexcoord_vert.h"
|
#include "DrawViewportQuadTransformTexcoord_vert.h"
|
||||||
#include "DrawTexture_frag.h"
|
#include "DrawTexture_frag.h"
|
||||||
|
#include "DrawTextureOpaque_frag.h"
|
||||||
#include "DrawColoredTexture_frag.h"
|
#include "DrawColoredTexture_frag.h"
|
||||||
|
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
|
@ -24,6 +25,7 @@ ShaderPointer StandardShaderLib::_drawTransformUnitQuadVS;
|
||||||
ShaderPointer StandardShaderLib::_drawTexcoordRectTransformUnitQuadVS;
|
ShaderPointer StandardShaderLib::_drawTexcoordRectTransformUnitQuadVS;
|
||||||
ShaderPointer StandardShaderLib::_drawViewportQuadTransformTexcoordVS;
|
ShaderPointer StandardShaderLib::_drawViewportQuadTransformTexcoordVS;
|
||||||
ShaderPointer StandardShaderLib::_drawTexturePS;
|
ShaderPointer StandardShaderLib::_drawTexturePS;
|
||||||
|
ShaderPointer StandardShaderLib::_drawTextureOpaquePS;
|
||||||
ShaderPointer StandardShaderLib::_drawColoredTexturePS;
|
ShaderPointer StandardShaderLib::_drawColoredTexturePS;
|
||||||
StandardShaderLib::ProgramMap StandardShaderLib::_programs;
|
StandardShaderLib::ProgramMap StandardShaderLib::_programs;
|
||||||
|
|
||||||
|
@ -82,6 +84,15 @@ ShaderPointer StandardShaderLib::getDrawTexturePS() {
|
||||||
return _drawTexturePS;
|
return _drawTexturePS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() {
|
||||||
|
if (!_drawTextureOpaquePS) {
|
||||||
|
_drawTextureOpaquePS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(DrawTextureOpaque_frag)));
|
||||||
|
}
|
||||||
|
return _drawTextureOpaquePS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ShaderPointer StandardShaderLib::getDrawColoredTexturePS() {
|
ShaderPointer StandardShaderLib::getDrawColoredTexturePS() {
|
||||||
if (!_drawColoredTexturePS) {
|
if (!_drawColoredTexturePS) {
|
||||||
_drawColoredTexturePS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(DrawColoredTexture_frag)));
|
_drawColoredTexturePS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(DrawColoredTexture_frag)));
|
||||||
|
|
|
@ -35,6 +35,7 @@ public:
|
||||||
static ShaderPointer getDrawViewportQuadTransformTexcoordVS();
|
static ShaderPointer getDrawViewportQuadTransformTexcoordVS();
|
||||||
|
|
||||||
static ShaderPointer getDrawTexturePS();
|
static ShaderPointer getDrawTexturePS();
|
||||||
|
static ShaderPointer getDrawTextureOpaquePS();
|
||||||
static ShaderPointer getDrawColoredTexturePS();
|
static ShaderPointer getDrawColoredTexturePS();
|
||||||
|
|
||||||
// The shader program combining the shaders available above, so they are unique
|
// The shader program combining the shaders available above, so they are unique
|
||||||
|
@ -47,6 +48,7 @@ protected:
|
||||||
static ShaderPointer _drawTexcoordRectTransformUnitQuadVS;
|
static ShaderPointer _drawTexcoordRectTransformUnitQuadVS;
|
||||||
static ShaderPointer _drawViewportQuadTransformTexcoordVS;
|
static ShaderPointer _drawViewportQuadTransformTexcoordVS;
|
||||||
static ShaderPointer _drawTexturePS;
|
static ShaderPointer _drawTexturePS;
|
||||||
|
static ShaderPointer _drawTextureOpaquePS;
|
||||||
static ShaderPointer _drawColoredTexturePS;
|
static ShaderPointer _drawColoredTexturePS;
|
||||||
|
|
||||||
typedef std::map<std::pair<GetShader, GetShader>, ShaderPointer> ProgramMap;
|
typedef std::map<std::pair<GetShader, GetShader>, ShaderPointer> ProgramMap;
|
||||||
|
|
|
@ -110,7 +110,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
||||||
} else {
|
} else {
|
||||||
// skybox has no cubemap, just clear the color buffer
|
// skybox has no cubemap, just clear the color buffer
|
||||||
auto color = skybox.getColor();
|
auto color = skybox.getColor();
|
||||||
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.0f, 0);
|
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.0f, 0, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -280,7 +280,7 @@ void PacketReceiver::processDatagrams() {
|
||||||
|
|
||||||
auto it = _packetListenerMap.find(packet->getType());
|
auto it = _packetListenerMap.find(packet->getType());
|
||||||
|
|
||||||
if (it != _packetListenerMap.end()) {
|
if (it != _packetListenerMap.end() && it->second.isValid()) {
|
||||||
|
|
||||||
auto listener = it.value();
|
auto listener = it.value();
|
||||||
|
|
||||||
|
@ -367,10 +367,12 @@ void PacketReceiver::processDatagrams() {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "No listener found for packet type " << nameForPacketType(packet->getType());
|
if (it == _packetListenerMap.end()) {
|
||||||
|
qWarning() << "No listener found for packet type " << nameForPacketType(packet->getType());
|
||||||
// insert a dummy listener so we don't print this again
|
|
||||||
_packetListenerMap.insert(packet->getType(), { nullptr, QMetaMethod() });
|
// insert a dummy listener so we don't print this again
|
||||||
|
_packetListenerMap.insert(packet->getType(), { nullptr, QMetaMethod() });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_packetListenerLock.unlock();
|
_packetListenerLock.unlock();
|
||||||
|
|
|
@ -220,13 +220,17 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu
|
||||||
|
|
||||||
void DeferredLightingEffect::prepare(RenderArgs* args) {
|
void DeferredLightingEffect::prepare(RenderArgs* args) {
|
||||||
gpu::Batch batch;
|
gpu::Batch batch;
|
||||||
|
|
||||||
// clear the normal and specular buffers
|
|
||||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
|
||||||
const float MAX_SPECULAR_EXPONENT = 128.0f;
|
|
||||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR2, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f / MAX_SPECULAR_EXPONENT));
|
|
||||||
|
|
||||||
args->_context->syncCache();
|
batch.setStateScissorRect(args->_viewport);
|
||||||
|
|
||||||
|
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
|
||||||
|
|
||||||
|
batch.setFramebuffer(primaryFbo);
|
||||||
|
// clear the normal and specular buffers
|
||||||
|
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
|
||||||
|
const float MAX_SPECULAR_EXPONENT = 128.0f;
|
||||||
|
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR2, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f / MAX_SPECULAR_EXPONENT), true);
|
||||||
|
|
||||||
args->_context->render(batch);
|
args->_context->render(batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,8 +249,9 @@ void DeferredLightingEffect::render(RenderArgs* args) {
|
||||||
batch.setFramebuffer(_copyFBO);
|
batch.setFramebuffer(_copyFBO);
|
||||||
|
|
||||||
batch.setViewportTransform(args->_viewport);
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
batch.setStateScissorRect(args->_viewport);
|
||||||
|
|
||||||
batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
|
||||||
|
|
||||||
batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture());
|
batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture());
|
||||||
|
|
||||||
|
@ -533,7 +538,6 @@ void DeferredLightingEffect::render(RenderArgs* args) {
|
||||||
batch.setResourceTexture(2, nullptr);
|
batch.setResourceTexture(2, nullptr);
|
||||||
batch.setResourceTexture(3, nullptr);
|
batch.setResourceTexture(3, nullptr);
|
||||||
|
|
||||||
args->_context->syncCache();
|
|
||||||
args->_context->render(batch);
|
args->_context->render(batch);
|
||||||
|
|
||||||
// End of the Lighting pass
|
// End of the Lighting pass
|
||||||
|
@ -546,7 +550,8 @@ void DeferredLightingEffect::copyBack(RenderArgs* args) {
|
||||||
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
||||||
|
|
||||||
// TODO why doesn't this blit work? It only seems to affect a small area below the rear view mirror.
|
// TODO why doesn't this blit work? It only seems to affect a small area below the rear view mirror.
|
||||||
auto destFbo = framebufferCache->getPrimaryFramebuffer();
|
// auto destFbo = framebufferCache->getPrimaryFramebuffer();
|
||||||
|
auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor();
|
||||||
// gpu::Vec4i vp = args->_viewport;
|
// gpu::Vec4i vp = args->_viewport;
|
||||||
// batch.blit(_copyFBO, vp, framebufferCache->getPrimaryFramebuffer(), vp);
|
// batch.blit(_copyFBO, vp, framebufferCache->getPrimaryFramebuffer(), vp);
|
||||||
batch.setFramebuffer(destFbo);
|
batch.setFramebuffer(destFbo);
|
||||||
|
@ -565,11 +570,6 @@ void DeferredLightingEffect::copyBack(RenderArgs* args) {
|
||||||
batch.setModelTransform(model);
|
batch.setModelTransform(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum buffers[3];
|
|
||||||
int bufferCount = 0;
|
|
||||||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
|
|
||||||
batch._glDrawBuffers(bufferCount, buffers);
|
|
||||||
|
|
||||||
batch.setResourceTexture(0, _copyFBO->getRenderBuffer(0));
|
batch.setResourceTexture(0, _copyFBO->getRenderBuffer(0));
|
||||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||||
|
|
||||||
|
|
|
@ -34,17 +34,20 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) {
|
||||||
//If the size changed, we need to delete our FBOs
|
//If the size changed, we need to delete our FBOs
|
||||||
if (_frameBufferSize != frameBufferSize) {
|
if (_frameBufferSize != frameBufferSize) {
|
||||||
_frameBufferSize = frameBufferSize;
|
_frameBufferSize = frameBufferSize;
|
||||||
_primaryFramebuffer.reset();
|
_primaryFramebufferFull.reset();
|
||||||
|
_primaryFramebufferDepthColor.reset();
|
||||||
_primaryDepthTexture.reset();
|
_primaryDepthTexture.reset();
|
||||||
_primaryColorTexture.reset();
|
_primaryColorTexture.reset();
|
||||||
_primaryNormalTexture.reset();
|
_primaryNormalTexture.reset();
|
||||||
_primarySpecularTexture.reset();
|
_primarySpecularTexture.reset();
|
||||||
|
_selfieFramebuffer.reset();
|
||||||
_cachedFramebuffers.clear();
|
_cachedFramebuffers.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramebufferCache::createPrimaryFramebuffer() {
|
void FramebufferCache::createPrimaryFramebuffer() {
|
||||||
_primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
_primaryFramebufferFull = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||||
|
_primaryFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||||
|
|
||||||
auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
||||||
auto width = _frameBufferSize.width();
|
auto width = _frameBufferSize.width();
|
||||||
|
@ -55,24 +58,37 @@ void FramebufferCache::createPrimaryFramebuffer() {
|
||||||
_primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
_primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||||
_primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
_primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||||
|
|
||||||
_primaryFramebuffer->setRenderBuffer(0, _primaryColorTexture);
|
_primaryFramebufferFull->setRenderBuffer(0, _primaryColorTexture);
|
||||||
_primaryFramebuffer->setRenderBuffer(1, _primaryNormalTexture);
|
_primaryFramebufferFull->setRenderBuffer(1, _primaryNormalTexture);
|
||||||
_primaryFramebuffer->setRenderBuffer(2, _primarySpecularTexture);
|
_primaryFramebufferFull->setRenderBuffer(2, _primarySpecularTexture);
|
||||||
|
|
||||||
|
_primaryFramebufferDepthColor->setRenderBuffer(0, _primaryColorTexture);
|
||||||
|
|
||||||
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
|
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
|
||||||
_primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler));
|
_primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler));
|
||||||
|
|
||||||
_primaryFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
_primaryFramebufferFull->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||||
|
|
||||||
|
_primaryFramebufferDepthColor->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||||
|
|
||||||
|
_selfieFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||||
|
auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler));
|
||||||
|
_selfieFramebuffer->setRenderBuffer(0, tex);
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::FramebufferPointer FramebufferCache::getPrimaryFramebuffer() {
|
gpu::FramebufferPointer FramebufferCache::getPrimaryFramebuffer() {
|
||||||
if (!_primaryFramebuffer) {
|
if (!_primaryFramebufferFull) {
|
||||||
createPrimaryFramebuffer();
|
createPrimaryFramebuffer();
|
||||||
}
|
}
|
||||||
return _primaryFramebuffer;
|
return _primaryFramebufferFull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpu::FramebufferPointer FramebufferCache::getPrimaryFramebufferDepthColor() {
|
||||||
|
if (!_primaryFramebufferDepthColor) {
|
||||||
|
createPrimaryFramebuffer();
|
||||||
|
}
|
||||||
|
return _primaryFramebufferDepthColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gpu::TexturePointer FramebufferCache::getPrimaryDepthTexture() {
|
gpu::TexturePointer FramebufferCache::getPrimaryDepthTexture() {
|
||||||
|
@ -112,7 +128,6 @@ gpu::FramebufferPointer FramebufferCache::getFramebuffer() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FramebufferCache::releaseFramebuffer(const gpu::FramebufferPointer& framebuffer) {
|
void FramebufferCache::releaseFramebuffer(const gpu::FramebufferPointer& framebuffer) {
|
||||||
if (QSize(framebuffer->getSize().x, framebuffer->getSize().y) == _frameBufferSize) {
|
if (QSize(framebuffer->getSize().x, framebuffer->getSize().y) == _frameBufferSize) {
|
||||||
_cachedFramebuffers.push_back(framebuffer);
|
_cachedFramebuffers.push_back(framebuffer);
|
||||||
|
@ -126,3 +141,10 @@ gpu::FramebufferPointer FramebufferCache::getShadowFramebuffer() {
|
||||||
}
|
}
|
||||||
return _shadowFramebuffer;
|
return _shadowFramebuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpu::FramebufferPointer FramebufferCache::getSelfieFramebuffer() {
|
||||||
|
if (!_selfieFramebuffer) {
|
||||||
|
createPrimaryFramebuffer();
|
||||||
|
}
|
||||||
|
return _selfieFramebuffer;
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ public:
|
||||||
/// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is
|
/// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is
|
||||||
/// used for scene rendering.
|
/// used for scene rendering.
|
||||||
gpu::FramebufferPointer getPrimaryFramebuffer();
|
gpu::FramebufferPointer getPrimaryFramebuffer();
|
||||||
|
gpu::FramebufferPointer getPrimaryFramebufferDepthColor();
|
||||||
|
|
||||||
gpu::TexturePointer getPrimaryDepthTexture();
|
gpu::TexturePointer getPrimaryDepthTexture();
|
||||||
gpu::TexturePointer getPrimaryColorTexture();
|
gpu::TexturePointer getPrimaryColorTexture();
|
||||||
|
@ -39,8 +40,12 @@ public:
|
||||||
/// Returns the framebuffer object used to render shadow maps;
|
/// Returns the framebuffer object used to render shadow maps;
|
||||||
gpu::FramebufferPointer getShadowFramebuffer();
|
gpu::FramebufferPointer getShadowFramebuffer();
|
||||||
|
|
||||||
|
/// Returns the framebuffer object used to render selfie maps;
|
||||||
|
gpu::FramebufferPointer getSelfieFramebuffer();
|
||||||
|
|
||||||
/// Returns a free framebuffer with a single color attachment for temp or intra-frame operations
|
/// Returns a free framebuffer with a single color attachment for temp or intra-frame operations
|
||||||
gpu::FramebufferPointer getFramebuffer();
|
gpu::FramebufferPointer getFramebuffer();
|
||||||
|
|
||||||
// TODO add sync functionality to the release, so we don't reuse a framebuffer being read from
|
// TODO add sync functionality to the release, so we don't reuse a framebuffer being read from
|
||||||
/// Releases a free framebuffer back for reuse
|
/// Releases a free framebuffer back for reuse
|
||||||
void releaseFramebuffer(const gpu::FramebufferPointer& framebuffer);
|
void releaseFramebuffer(const gpu::FramebufferPointer& framebuffer);
|
||||||
|
@ -51,13 +56,17 @@ private:
|
||||||
|
|
||||||
void createPrimaryFramebuffer();
|
void createPrimaryFramebuffer();
|
||||||
|
|
||||||
gpu::FramebufferPointer _primaryFramebuffer;
|
gpu::FramebufferPointer _primaryFramebufferFull;
|
||||||
|
gpu::FramebufferPointer _primaryFramebufferDepthColor;
|
||||||
gpu::TexturePointer _primaryDepthTexture;
|
gpu::TexturePointer _primaryDepthTexture;
|
||||||
gpu::TexturePointer _primaryColorTexture;
|
gpu::TexturePointer _primaryColorTexture;
|
||||||
gpu::TexturePointer _primaryNormalTexture;
|
gpu::TexturePointer _primaryNormalTexture;
|
||||||
gpu::TexturePointer _primarySpecularTexture;
|
gpu::TexturePointer _primarySpecularTexture;
|
||||||
|
|
||||||
gpu::FramebufferPointer _shadowFramebuffer;
|
gpu::FramebufferPointer _shadowFramebuffer;
|
||||||
|
|
||||||
|
gpu::FramebufferPointer _selfieFramebuffer;
|
||||||
|
|
||||||
QSize _frameBufferSize{ 100, 100 };
|
QSize _frameBufferSize{ 100, 100 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include "standardTransformPNTC_vert.h"
|
#include "standardTransformPNTC_vert.h"
|
||||||
#include "standardDrawTexture_frag.h"
|
#include "standardDrawTexture_frag.h"
|
||||||
|
|
||||||
|
#include "gpu/StandardShaderLib.h"
|
||||||
|
|
||||||
//#define WANT_DEBUG
|
//#define WANT_DEBUG
|
||||||
|
|
||||||
const int GeometryCache::UNKNOWN_ID = -1;
|
const int GeometryCache::UNKNOWN_ID = -1;
|
||||||
|
@ -1651,7 +1653,7 @@ QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QS
|
||||||
return geometry.staticCast<Resource>();
|
return geometry.staticCast<Resource>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch) {
|
void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
|
||||||
if (!_standardDrawPipeline) {
|
if (!_standardDrawPipeline) {
|
||||||
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)));
|
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)));
|
||||||
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag)));
|
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag)));
|
||||||
|
@ -1660,12 +1662,24 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch) {
|
||||||
|
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
|
|
||||||
|
|
||||||
// enable decal blend
|
// enable decal blend
|
||||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||||
|
|
||||||
_standardDrawPipeline.reset(gpu::Pipeline::create(program, state));
|
_standardDrawPipeline.reset(gpu::Pipeline::create(program, state));
|
||||||
|
|
||||||
|
|
||||||
|
auto stateNoBlend = std::make_shared<gpu::State>();
|
||||||
|
auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS();
|
||||||
|
auto programNoBlend = gpu::ShaderPointer(gpu::Shader::createProgram(vs, noBlendPS));
|
||||||
|
gpu::Shader::makeProgram((*programNoBlend));
|
||||||
|
_standardDrawPipelineNoBlend.reset(gpu::Pipeline::create(programNoBlend, stateNoBlend));
|
||||||
|
}
|
||||||
|
if (noBlend) {
|
||||||
|
batch.setPipeline(_standardDrawPipelineNoBlend);
|
||||||
|
} else {
|
||||||
|
batch.setPipeline(_standardDrawPipeline);
|
||||||
}
|
}
|
||||||
batch.setPipeline(_standardDrawPipeline);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float NetworkGeometry::NO_HYSTERESIS = -1.0f;
|
const float NetworkGeometry::NO_HYSTERESIS = -1.0f;
|
||||||
|
|
|
@ -206,7 +206,7 @@ public:
|
||||||
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
|
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
|
||||||
|
|
||||||
/// Set a batch to the simple pipeline, returning the previous pipeline
|
/// Set a batch to the simple pipeline, returning the previous pipeline
|
||||||
void useSimpleDrawPipeline(gpu::Batch& batch);
|
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -221,6 +221,7 @@ private:
|
||||||
typedef QPair<unsigned int, unsigned int> VerticesIndices;
|
typedef QPair<unsigned int, unsigned int> VerticesIndices;
|
||||||
|
|
||||||
gpu::PipelinePointer _standardDrawPipeline;
|
gpu::PipelinePointer _standardDrawPipeline;
|
||||||
|
gpu::PipelinePointer _standardDrawPipelineNoBlend;
|
||||||
QHash<float, gpu::BufferPointer> _cubeVerticies;
|
QHash<float, gpu::BufferPointer> _cubeVerticies;
|
||||||
QHash<Vec2Pair, gpu::BufferPointer> _cubeColors;
|
QHash<Vec2Pair, gpu::BufferPointer> _cubeColors;
|
||||||
gpu::BufferPointer _wireCubeIndexBuffer;
|
gpu::BufferPointer _wireCubeIndexBuffer;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "FboCache.h"
|
#include "FboCache.h"
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
#include <NumericalConstants.h>
|
||||||
|
|
||||||
class QMyQuickRenderControl : public QQuickRenderControl {
|
class QMyQuickRenderControl : public QQuickRenderControl {
|
||||||
protected:
|
protected:
|
||||||
|
@ -44,7 +45,10 @@ Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
|
||||||
// Time between receiving a request to render the offscreen UI actually triggering
|
// Time between receiving a request to render the offscreen UI actually triggering
|
||||||
// the render. Could possibly be increased depending on the framerate we expect to
|
// the render. Could possibly be increased depending on the framerate we expect to
|
||||||
// achieve.
|
// achieve.
|
||||||
static const int SMALL_INTERVAL = 5;
|
static const int MAX_QML_FRAMERATE = 10;
|
||||||
|
static const int MIN_RENDER_INTERVAL_US = USECS_PER_SECOND / MAX_QML_FRAMERATE;
|
||||||
|
static const int MIN_TIMER_MS = 5;
|
||||||
|
|
||||||
|
|
||||||
OffscreenQmlSurface::OffscreenQmlSurface() :
|
OffscreenQmlSurface::OffscreenQmlSurface() :
|
||||||
_renderControl(new QMyQuickRenderControl), _fboCache(new FboCache) {
|
_renderControl(new QMyQuickRenderControl), _fboCache(new FboCache) {
|
||||||
|
@ -90,7 +94,6 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
||||||
// When Quick says there is a need to render, we will not render immediately. Instead,
|
// When Quick says there is a need to render, we will not render immediately. Instead,
|
||||||
// a timer with a small interval is used to get better performance.
|
// a timer with a small interval is used to get better performance.
|
||||||
_updateTimer.setSingleShot(true);
|
_updateTimer.setSingleShot(true);
|
||||||
_updateTimer.setInterval(SMALL_INTERVAL);
|
|
||||||
connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
|
connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
|
||||||
|
|
||||||
// Now hook up the signals. For simplicy we don't differentiate between
|
// Now hook up the signals. For simplicy we don't differentiate between
|
||||||
|
@ -170,13 +173,18 @@ QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQm
|
||||||
|
|
||||||
void OffscreenQmlSurface::requestUpdate() {
|
void OffscreenQmlSurface::requestUpdate() {
|
||||||
_polish = true;
|
_polish = true;
|
||||||
if (!_updateTimer.isActive()) {
|
requestRender();
|
||||||
_updateTimer.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::requestRender() {
|
void OffscreenQmlSurface::requestRender() {
|
||||||
if (!_updateTimer.isActive()) {
|
if (!_updateTimer.isActive()) {
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
auto lastInterval = now - _lastRenderTime;
|
||||||
|
if (lastInterval > MIN_RENDER_INTERVAL_US) {
|
||||||
|
_updateTimer.setInterval(MIN_TIMER_MS);
|
||||||
|
} else {
|
||||||
|
_updateTimer.setInterval((MIN_RENDER_INTERVAL_US - lastInterval) / USECS_PER_MSEC);
|
||||||
|
}
|
||||||
_updateTimer.start();
|
_updateTimer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,6 +251,7 @@ void OffscreenQmlSurface::updateQuick() {
|
||||||
if (_paused) {
|
if (_paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!makeCurrent()) {
|
if (!makeCurrent()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -270,11 +279,11 @@ void OffscreenQmlSurface::updateQuick() {
|
||||||
// Need a debug context with sync logging to figure out why.
|
// Need a debug context with sync logging to figure out why.
|
||||||
// for now just clear the errors
|
// for now just clear the errors
|
||||||
glGetError();
|
glGetError();
|
||||||
// Q_ASSERT(!glGetError());
|
|
||||||
|
|
||||||
_quickWindow->resetOpenGLState();
|
_quickWindow->resetOpenGLState();
|
||||||
|
|
||||||
QOpenGLFramebufferObject::bindDefault();
|
QOpenGLFramebufferObject::bindDefault();
|
||||||
|
_lastRenderTime = usecTimestampNow();
|
||||||
// Force completion of all the operations before we emit the texture as being ready for use
|
// Force completion of all the operations before we emit the texture as being ready for use
|
||||||
glFinish();
|
glFinish();
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ private:
|
||||||
QQuickItem* _rootItem{ nullptr };
|
QQuickItem* _rootItem{ nullptr };
|
||||||
QTimer _updateTimer;
|
QTimer _updateTimer;
|
||||||
FboCache* _fboCache;
|
FboCache* _fboCache;
|
||||||
|
quint64 _lastRenderTime{ 0 };
|
||||||
bool _polish{ true };
|
bool _polish{ true };
|
||||||
bool _paused{ true };
|
bool _paused{ true };
|
||||||
MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p; } };
|
MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p; } };
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <RenderArgs.h>
|
#include <RenderArgs.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
|
|
||||||
|
#include "FramebufferCache.h"
|
||||||
#include "DeferredLightingEffect.h"
|
#include "DeferredLightingEffect.h"
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
|
|
||||||
|
@ -27,6 +28,26 @@
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
|
void SetupDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||||
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
|
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferDepthColor();
|
||||||
|
|
||||||
|
gpu::Batch batch;
|
||||||
|
batch.setFramebuffer(nullptr);
|
||||||
|
batch.setFramebuffer(primaryFbo);
|
||||||
|
|
||||||
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
batch.setStateScissorRect(args->_viewport);
|
||||||
|
|
||||||
|
batch.clearFramebuffer(
|
||||||
|
gpu::Framebuffer::BUFFER_COLOR0 |
|
||||||
|
gpu::Framebuffer::BUFFER_DEPTH,
|
||||||
|
vec4(vec3(0), 1), 1.0, 0.0, true);
|
||||||
|
|
||||||
|
args->_context->render(batch);
|
||||||
|
}
|
||||||
|
|
||||||
void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||||
DependencyManager::get<DeferredLightingEffect>()->prepare(renderContext->args);
|
DependencyManager::get<DeferredLightingEffect>()->prepare(renderContext->args);
|
||||||
}
|
}
|
||||||
|
@ -41,6 +62,7 @@ void ResolveDeferred::run(const SceneContextPointer& sceneContext, const RenderC
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderDeferredTask::RenderDeferredTask() : Task() {
|
RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
|
_jobs.push_back(Job(new SetupDeferred::JobModel("SetupFramebuffer")));
|
||||||
_jobs.push_back(Job(new DrawBackground::JobModel("DrawBackground")));
|
_jobs.push_back(Job(new DrawBackground::JobModel("DrawBackground")));
|
||||||
|
|
||||||
_jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred")));
|
_jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred")));
|
||||||
|
@ -56,7 +78,6 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
auto& renderedOpaques = _jobs.back().getOutput();
|
auto& renderedOpaques = _jobs.back().getOutput();
|
||||||
_jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput())));
|
_jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput())));
|
||||||
_jobs.push_back(Job(new DrawLight::JobModel("DrawLight")));
|
_jobs.push_back(Job(new DrawLight::JobModel("DrawLight")));
|
||||||
_jobs.push_back(Job(new ResetGLState::JobModel()));
|
|
||||||
_jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred")));
|
_jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred")));
|
||||||
_jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred")));
|
_jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred")));
|
||||||
_jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent",
|
_jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent",
|
||||||
|
@ -133,21 +154,12 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend
|
||||||
batch.setViewTransform(viewMat);
|
batch.setViewTransform(viewMat);
|
||||||
|
|
||||||
{
|
{
|
||||||
GLenum buffers[3];
|
|
||||||
int bufferCount = 0;
|
|
||||||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
|
|
||||||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
|
|
||||||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
|
|
||||||
batch._glDrawBuffers(bufferCount, buffers);
|
|
||||||
const float OPAQUE_ALPHA_THRESHOLD = 0.5f;
|
const float OPAQUE_ALPHA_THRESHOLD = 0.5f;
|
||||||
args->_alphaThreshold = OPAQUE_ALPHA_THRESHOLD;
|
args->_alphaThreshold = OPAQUE_ALPHA_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOpaqueItems);
|
renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOpaqueItems);
|
||||||
|
|
||||||
// Before rendering the batch make sure we re in sync with gl state
|
|
||||||
args->_context->syncCache();
|
|
||||||
renderContext->args->_context->syncCache();
|
|
||||||
args->_context->render((*args->_batch));
|
args->_context->render((*args->_batch));
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -171,21 +183,15 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const
|
||||||
}
|
}
|
||||||
batch.setProjectionTransform(projMat);
|
batch.setProjectionTransform(projMat);
|
||||||
batch.setViewTransform(viewMat);
|
batch.setViewTransform(viewMat);
|
||||||
const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
GLenum buffers[3];
|
const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
|
||||||
int bufferCount = 0;
|
|
||||||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
|
|
||||||
batch._glDrawBuffers(bufferCount, buffers);
|
|
||||||
args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD;
|
args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnTransparentItems);
|
renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnTransparentItems);
|
||||||
|
|
||||||
// Before rendering the batch make sure we re in sync with gl state
|
|
||||||
args->_context->syncCache();
|
|
||||||
args->_context->render((*args->_batch));
|
args->_context->render((*args->_batch));
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -239,17 +245,17 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
|
||||||
}
|
}
|
||||||
batch.setProjectionTransform(projMat);
|
batch.setProjectionTransform(projMat);
|
||||||
batch.setViewTransform(viewMat);
|
batch.setViewTransform(viewMat);
|
||||||
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
batch.setStateScissorRect(args->_viewport);
|
||||||
|
|
||||||
batch.setPipeline(getOpaquePipeline());
|
batch.setPipeline(getOpaquePipeline());
|
||||||
batch.setResourceTexture(0, args->_whiteTexture);
|
batch.setResourceTexture(0, args->_whiteTexture);
|
||||||
|
|
||||||
if (!inItems.empty()) {
|
if (!inItems.empty()) {
|
||||||
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0);
|
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0, true);
|
||||||
renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOverlay3DItems);
|
renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOverlay3DItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before rendering the batch make sure we re in sync with gl state
|
|
||||||
args->_context->syncCache();
|
|
||||||
args->_context->render((*args->_batch));
|
args->_context->render((*args->_batch));
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
args->_whiteTexture.reset();
|
args->_whiteTexture.reset();
|
||||||
|
|
|
@ -16,6 +16,13 @@
|
||||||
|
|
||||||
#include "gpu/Pipeline.h"
|
#include "gpu/Pipeline.h"
|
||||||
|
|
||||||
|
class SetupDeferred {
|
||||||
|
public:
|
||||||
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||||
|
|
||||||
|
typedef render::Job::Model<SetupDeferred> JobModel;
|
||||||
|
};
|
||||||
|
|
||||||
class PrepareDeferred {
|
class PrepareDeferred {
|
||||||
public:
|
public:
|
||||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||||
|
|
|
@ -118,6 +118,13 @@ void vhacd::VHACDUtil::fattenMeshes(const FBXMesh& mesh, FBXMesh& result,
|
||||||
glm::vec3 p2 = result.vertices[index2];
|
glm::vec3 p2 = result.vertices[index2];
|
||||||
glm::vec3 av = (p0 + p1 + p2) / 3.0f; // center of the triangular face
|
glm::vec3 av = (p0 + p1 + p2) / 3.0f; // center of the triangular face
|
||||||
|
|
||||||
|
glm::vec3 normal = glm::normalize(glm::cross(p1 - p0, p2 - p0));
|
||||||
|
float threshold = 1.0f / sqrtf(3.0f);
|
||||||
|
if (normal.y > -threshold && normal.y < threshold) {
|
||||||
|
// this triangle is more a wall than a floor, skip it.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
float dropAmount = 0;
|
float dropAmount = 0;
|
||||||
dropAmount = glm::max(glm::length(p1 - p0), dropAmount);
|
dropAmount = glm::max(glm::length(p1 - p0), dropAmount);
|
||||||
dropAmount = glm::max(glm::length(p2 - p1), dropAmount);
|
dropAmount = glm::max(glm::length(p2 - p1), dropAmount);
|
||||||
|
|
Loading…
Reference in a new issue