mirror of
https://github.com/lubosz/overte.git
synced 2025-04-09 13:12:57 +02:00
merge with master
This commit is contained in:
commit
a37b089b33
82 changed files with 2130 additions and 958 deletions
|
@ -66,6 +66,9 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
|
|||
// set the logging target to the the CHILD_TARGET_NAME
|
||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
||||
|
||||
// make sure we output process IDs for a child AC otherwise it's insane to parse
|
||||
LogHandler::getInstance().setShouldOutputPID(true);
|
||||
|
||||
// setup our _requestAssignment member variable from the passed arguments
|
||||
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
|||
_walletUUID(walletUUID),
|
||||
_assignmentServerHostname(assignmentServerHostname),
|
||||
_assignmentServerPort(assignmentServerPort)
|
||||
{
|
||||
{
|
||||
qDebug() << "_requestAssignmentType =" << _requestAssignmentType;
|
||||
|
||||
|
||||
// start the Logging class with the parent's target name
|
||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
||||
|
||||
|
@ -77,13 +77,13 @@ void AssignmentClientMonitor::simultaneousWaitOnChildren(int waitMsecs) {
|
|||
while(_childProcesses.size() > 0 && !waitTimer.hasExpired(waitMsecs)) {
|
||||
// continue processing events so we can handle a process finishing up
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::childProcessFinished() {
|
||||
QProcess* childProcess = qobject_cast<QProcess*>(sender());
|
||||
qint64 processID = _childProcesses.key(childProcess);
|
||||
|
||||
|
||||
if (processID > 0) {
|
||||
qDebug() << "Child process" << processID << "has finished. Removing from internal map.";
|
||||
_childProcesses.remove(processID);
|
||||
|
@ -98,17 +98,17 @@ void AssignmentClientMonitor::stopChildProcesses() {
|
|||
qDebug() << "Attempting to terminate child process" << childProcess->processId();
|
||||
childProcess->terminate();
|
||||
}
|
||||
|
||||
|
||||
simultaneousWaitOnChildren(WAIT_FOR_CHILD_MSECS);
|
||||
|
||||
|
||||
if (_childProcesses.size() > 0) {
|
||||
// ask even more firmly
|
||||
foreach(QProcess* childProcess, _childProcesses) {
|
||||
qDebug() << "Attempting to kill child process" << childProcess->processId();
|
||||
childProcess->kill();
|
||||
}
|
||||
|
||||
simultaneousWaitOnChildren(WAIT_FOR_CHILD_MSECS);
|
||||
|
||||
simultaneousWaitOnChildren(WAIT_FOR_CHILD_MSECS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ void AssignmentClientMonitor::aboutToQuit() {
|
|||
void AssignmentClientMonitor::spawnChildClient() {
|
||||
QProcess* assignmentClient = new QProcess(this);
|
||||
|
||||
|
||||
|
||||
// unparse the parts of the command-line that the child cares about
|
||||
QStringList _childArguments;
|
||||
if (_assignmentPool != "") {
|
||||
|
@ -153,7 +153,7 @@ void AssignmentClientMonitor::spawnChildClient() {
|
|||
|
||||
// make sure that the output from the child process appears in our output
|
||||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
|
||||
|
||||
assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments);
|
||||
|
||||
// make sure we hear that this process has finished when it does
|
||||
|
@ -194,7 +194,7 @@ void AssignmentClientMonitor::checkSpares() {
|
|||
qDebug() << "asking child" << aSpareId << "to exit.";
|
||||
SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId);
|
||||
childNode->activateLocalSocket();
|
||||
|
||||
|
||||
QByteArray diePacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, childNode);
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ void AssignmentClientMonitor::readPendingDatagrams() {
|
|||
// update our records about how to reach this child
|
||||
matchingNode->setLocalSocket(senderSockAddr);
|
||||
|
||||
QVariantMap packetVariantMap =
|
||||
QVariantMap packetVariantMap =
|
||||
JSONBreakableMarshal::fromStringBuffer(receivedPacket.mid(numBytesForPacketHeader(receivedPacket)));
|
||||
QJsonObject unpackedStatsJSON = QJsonObject::fromVariantMap(packetVariantMap);
|
||||
|
||||
|
|
|
@ -850,7 +850,9 @@ void AudioMixer::run() {
|
|||
|
||||
++_numStatFrames;
|
||||
|
||||
// since we're a while loop we need to help Qt's event processing
|
||||
QCoreApplication::processEvents();
|
||||
QCoreApplication::sendPostedEvents(this, 0);
|
||||
|
||||
if (_isFinished) {
|
||||
break;
|
||||
|
|
2
cmake/externals/polyvox/CMakeLists.txt
vendored
2
cmake/externals/polyvox/CMakeLists.txt
vendored
|
@ -5,7 +5,7 @@ ExternalProject_Add(
|
|||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/polyvox.zip
|
||||
URL_MD5 904b840328278c9b36fa7a14be730c34
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
CMAKE_ARGS -DENABLE_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
|
|
|
@ -99,6 +99,13 @@ var NUM_BUTTONS = 3;
|
|||
|
||||
var screenSize = Controller.getViewportDimensions();
|
||||
var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2;
|
||||
Script.include(["../../libraries/toolBars.js"]);
|
||||
const persistKey = "highfidelity.gun.toolbar.position";
|
||||
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
|
||||
toolBar.save = function () {
|
||||
Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
|
||||
};
|
||||
var old = JSON.parse(Settings.getValue(persistKey) || '0');
|
||||
var reticle = Overlays.addOverlay("image", {
|
||||
x: screenSize.x / 2 - (BUTTON_SIZE / 2),
|
||||
y: screenSize.y / 2 - (BUTTON_SIZE / 2),
|
||||
|
@ -108,9 +115,9 @@ var reticle = Overlays.addOverlay("image", {
|
|||
alpha: 1
|
||||
});
|
||||
|
||||
var offButton = Overlays.addOverlay("image", {
|
||||
x: startX,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
var offButton = toolBar.addOverlay("image", {
|
||||
x: old ? old[0] : startX,
|
||||
y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)),
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg",
|
||||
|
@ -118,7 +125,7 @@ var offButton = Overlays.addOverlay("image", {
|
|||
});
|
||||
|
||||
startX += BUTTON_SIZE + PADDING;
|
||||
var platformButton = Overlays.addOverlay("image", {
|
||||
var platformButton = toolBar.addOverlay("image", {
|
||||
x: startX,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
width: BUTTON_SIZE,
|
||||
|
@ -128,7 +135,7 @@ var platformButton = Overlays.addOverlay("image", {
|
|||
});
|
||||
|
||||
startX += BUTTON_SIZE + PADDING;
|
||||
var gridButton = Overlays.addOverlay("image", {
|
||||
var gridButton = toolBar.addOverlay("image", {
|
||||
x: startX,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
width: BUTTON_SIZE,
|
||||
|
@ -493,10 +500,8 @@ function mousePressEvent(event) {
|
|||
}
|
||||
|
||||
function scriptEnding() {
|
||||
Overlays.deleteOverlay(reticle);
|
||||
Overlays.deleteOverlay(offButton);
|
||||
Overlays.deleteOverlay(platformButton);
|
||||
Overlays.deleteOverlay(gridButton);
|
||||
Overlays.deleteOverlay(reticle);
|
||||
toolBar.cleanup();
|
||||
Overlays.deleteOverlay(pointer[0]);
|
||||
Overlays.deleteOverlay(pointer[1]);
|
||||
Overlays.deleteOverlay(text);
|
||||
|
|
|
@ -19,3 +19,4 @@ Script.load("grab.js");
|
|||
Script.load("pointer.js");
|
||||
Script.load("directory.js");
|
||||
Script.load("mouseLook.js");
|
||||
Script.load("dialTone.js");
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// examples
|
||||
//
|
||||
// Created by Stephen Birarda on 06/08/15.
|
||||
// Added disconnect HRS 6/11/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -10,14 +11,26 @@
|
|||
//
|
||||
|
||||
// setup the local sound we're going to use
|
||||
var connectSound = SoundCache.getSound("file://" + Paths.resources + "sounds/short1.wav");
|
||||
var connectSound = SoundCache.getSound("file:///" + Paths.resources + "sounds/hello.wav");
|
||||
var disconnectSound = SoundCache.getSound("file:///" + Paths.resources + "sounds/goodbye.wav");
|
||||
var micMutedSound = SoundCache.getSound("file:///" + Paths.resources + "sounds/goodbye.wav");
|
||||
|
||||
// setup the options needed for that sound
|
||||
var connectSoundOptions = {
|
||||
var soundOptions = {
|
||||
localOnly: true
|
||||
}
|
||||
};
|
||||
|
||||
// play the sound locally once we get the first audio packet from a mixer
|
||||
Audio.receivedFirstPacket.connect(function(){
|
||||
Audio.playSound(connectSound, connectSoundOptions);
|
||||
Audio.playSound(connectSound, soundOptions);
|
||||
});
|
||||
|
||||
Audio.disconnected.connect(function(){
|
||||
Audio.playSound(disconnectSound, soundOptions);
|
||||
});
|
||||
|
||||
AudioDevice.muteToggled.connect(function () {
|
||||
if (AudioDevice.getMuted()) {
|
||||
Audio.playSound(micMutedSound, soundOptions);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// examples
|
||||
//
|
||||
// Created by Philip Rosedale on February 2, 2015
|
||||
// Persist toolbar by HRS 6/11/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Press the dice button to throw some dice from the center of the screen.
|
||||
|
@ -31,9 +32,16 @@ var screenSize = Controller.getViewportDimensions();
|
|||
var BUTTON_SIZE = 32;
|
||||
var PADDING = 3;
|
||||
|
||||
var offButton = Overlays.addOverlay("image", {
|
||||
x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
Script.include(["libraries/toolBars.js"]);
|
||||
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
|
||||
const persistKey = "highfidelity.dice.toolbar.position";
|
||||
toolBar.save = function () {
|
||||
Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
|
||||
};
|
||||
var old = JSON.parse(Settings.getValue(persistKey) || '0');
|
||||
var offButton = toolBar.addOverlay("image", {
|
||||
x: old ? old[0] : (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING),
|
||||
y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)),
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",
|
||||
|
@ -45,7 +53,7 @@ var offButton = Overlays.addOverlay("image", {
|
|||
alpha: 1
|
||||
});
|
||||
|
||||
var deleteButton = Overlays.addOverlay("image", {
|
||||
var deleteButton = toolBar.addOverlay("image", {
|
||||
x: screenSize.x / 2 - BUTTON_SIZE,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
width: BUTTON_SIZE,
|
||||
|
@ -59,7 +67,7 @@ var deleteButton = Overlays.addOverlay("image", {
|
|||
alpha: 1
|
||||
});
|
||||
|
||||
var diceButton = Overlays.addOverlay("image", {
|
||||
var diceButton = toolBar.addOverlay("image", {
|
||||
x: screenSize.x / 2 + PADDING,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
width: BUTTON_SIZE,
|
||||
|
@ -140,10 +148,8 @@ function mousePressEvent(event) {
|
|||
}
|
||||
|
||||
function scriptEnding() {
|
||||
Overlays.deleteOverlay(offButton);
|
||||
Overlays.deleteOverlay(diceButton);
|
||||
Overlays.deleteOverlay(deleteButton);
|
||||
toolBar.cleanup();
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 10/2/14.
|
||||
// Persist toolbar by HRS 6/11/15.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This script allows you to edit entities with a new UI/UX for mouse and trackpad based editing
|
||||
|
@ -320,6 +321,7 @@ var toolBar = (function () {
|
|||
}
|
||||
}
|
||||
|
||||
const persistKey = "highfidelity.edit.toolbar.position";
|
||||
that.move = function () {
|
||||
var newViewPort,
|
||||
toolsX,
|
||||
|
@ -330,6 +332,15 @@ var toolBar = (function () {
|
|||
if (toolBar === undefined) {
|
||||
initialize();
|
||||
|
||||
toolBar.save = function () {
|
||||
Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
|
||||
};
|
||||
var old = JSON.parse(Settings.getValue(persistKey) || '0');
|
||||
if (old) {
|
||||
windowDimensions = newViewPort;
|
||||
toolBar.move(old[0], old[1]);
|
||||
return;
|
||||
}
|
||||
} else if (windowDimensions.x === newViewPort.x &&
|
||||
windowDimensions.y === newViewPort.y) {
|
||||
return;
|
||||
|
|
|
@ -354,7 +354,8 @@
|
|||
var elZoneAtmosphereScatteringWavelengthsZ = document.getElementById("property-zone-atmosphere-scattering-wavelengths-z");
|
||||
var elZoneAtmosphereHasStars = document.getElementById("property-zone-atmosphere-has-stars");
|
||||
|
||||
var elPolyVoxSelections = document.querySelectorAll(".poly-vox-section");
|
||||
var elPolyVoxSections = document.querySelectorAll(".poly-vox-section");
|
||||
allSections.push(elPolyVoxSections);
|
||||
var elVoxelVolumeSizeX = document.getElementById("property-voxel-volume-size-x");
|
||||
var elVoxelVolumeSizeY = document.getElementById("property-voxel-volume-size-y");
|
||||
var elVoxelVolumeSizeZ = document.getElementById("property-voxel-volume-size-z");
|
||||
|
@ -602,6 +603,10 @@
|
|||
elParticleLocalGravity.value = properties.localGravity.toFixed(2);
|
||||
elParticleRadius.value = properties.particleRadius.toFixed(3);
|
||||
} else if (properties.type == "PolyVox") {
|
||||
for (var i = 0; i < elPolyVoxSections.length; i++) {
|
||||
elPolyVoxSections[i].style.display = 'block';
|
||||
}
|
||||
|
||||
elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2);
|
||||
elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2);
|
||||
elVoxelVolumeSizeZ.value = properties.voxelVolumeSize.z.toFixed(2);
|
||||
|
@ -1014,9 +1019,9 @@
|
|||
<div class="poly-vox-section property">
|
||||
<div class="label">Voxel Volume Size</div>
|
||||
<div class="value">
|
||||
<div class="input-area">X <br><input class="coord" type='number' id="property-voxel-volume-size-x"></input></div>
|
||||
<div class="input-area">Y <br><input class="coord" type='number' id="property-voxel-volume-size-y"></input></div>
|
||||
<div class="input-area">Z <br><input class="coord" type='number' id="property-voxel-volume-size-z"></input></div>
|
||||
<div class="input-area">X <br> <input class="coord" type='number' id="property-voxel-volume-size-x"></input></div>
|
||||
<div class="input-area">Y <br><input class="coord" type='number' id="property-voxel-volume-size-y"></input></div>
|
||||
<div class="input-area">Z <br><input class="coord" type='number' id="property-voxel-volume-size-z"></input></div>
|
||||
</div>
|
||||
|
||||
<div class="label">Surface Extractor</div>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// examples
|
||||
//
|
||||
// Created by Clément Brisset on 5/7/14.
|
||||
// Persistable drag position by HRS 6/11/15.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -236,6 +237,7 @@ ToolBar = function(x, y, direction) {
|
|||
y: y - ToolBar.SPACING
|
||||
});
|
||||
}
|
||||
this.save();
|
||||
}
|
||||
|
||||
this.setAlpha = function(alpha, tool) {
|
||||
|
@ -313,9 +315,8 @@ ToolBar = function(x, y, direction) {
|
|||
this.cleanup = function() {
|
||||
for(var tool in this.tools) {
|
||||
this.tools[tool].cleanup();
|
||||
delete this.tools[tool];
|
||||
}
|
||||
|
||||
|
||||
if (this.back != null) {
|
||||
Overlays.deleteOverlay(this.back);
|
||||
this.back = null;
|
||||
|
@ -327,7 +328,71 @@ ToolBar = function(x, y, direction) {
|
|||
this.width = 0;
|
||||
this.height = 0;
|
||||
}
|
||||
|
||||
var that = this;
|
||||
this.contains = function (xOrPoint, optionalY) {
|
||||
var x = (optionalY === undefined) ? xOrPoint.x : xOrPoint,
|
||||
y = (optionalY === undefined) ? xOrPoint.y : optionalY;
|
||||
return (that.x <= x) && (x <= (that.x + that.width)) &&
|
||||
(that.y <= y) && (y <= (that.y + that.height));
|
||||
}
|
||||
that.hover = function (enable) {
|
||||
that.isHovering = enable;
|
||||
if (that.back) {
|
||||
if (enable) {
|
||||
that.oldAlpha = Overlays.getProperty(that.back, 'backgroundAlpha');
|
||||
}
|
||||
Overlays.editOverlay(this.back, {
|
||||
visible: enable,
|
||||
backgroundAlpha: enable ? 0.5 : that.oldAlpha
|
||||
});
|
||||
}
|
||||
};
|
||||
// These are currently only doing that which is necessary for toolbar hover and toolbar drag.
|
||||
// They have not yet been extended to tool hover/click/release, etc.
|
||||
this.mousePressEvent = function (event) {
|
||||
if (!that.contains(event)) {
|
||||
that.mightBeDragging = false;
|
||||
return;
|
||||
}
|
||||
that.mightBeDragging = true;
|
||||
that.dragOffsetX = that.x - event.x;
|
||||
that.dragOffsetY = that.y - event.y;
|
||||
};
|
||||
this.mouseMove = function (event) {
|
||||
if (!that.mightBeDragging || !event.isLeftButton) {
|
||||
that.mightBeDragging = false;
|
||||
if (!that.contains(event)) {
|
||||
if (that.isHovering) {
|
||||
that.hover(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!that.isHovering) {
|
||||
that.hover(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
that.move(that.dragOffsetX + event.x, that.dragOffsetY + event.y);
|
||||
};
|
||||
Controller.mousePressEvent.connect(this.mousePressEvent);
|
||||
Controller.mouseMoveEvent.connect(this.mouseMove);
|
||||
// Called on move. A different approach would be to have all this on the prototype,
|
||||
// and let apps extend where needed. Ex. app defines its toolbar.move() to call this.__proto__.move and then save.
|
||||
this.save = function () { };
|
||||
// This compatability hack breaks the model, but makes converting existing scripts easier:
|
||||
this.addOverlay = function (ignored, oldSchoolProperties) {
|
||||
var properties = JSON.parse(JSON.stringify(oldSchoolProperties)); // a copy
|
||||
if (that.numberOfTools() === 0) {
|
||||
that.move(properties.x, properties.y);
|
||||
}
|
||||
delete properties.x;
|
||||
delete properties.y;
|
||||
var index = that.addTool(properties);
|
||||
var id = that.tools[index].overlay();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
ToolBar.SPACING = 4;
|
||||
ToolBar.VERTICAL = 0;
|
||||
ToolBar.HORIZONTAL = 1;
|
||||
ToolBar.HORIZONTAL = 1;
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
Script.include('lineRider.js')
|
||||
var MAX_POINTS_PER_LINE = 80;
|
||||
|
||||
var MAX_POINTS_PER_LINE = 30;
|
||||
var LINE_LIFETIME = 60 * 5 //5 minute lifetime
|
||||
|
||||
var colorPalette = [{
|
||||
red: 236,
|
||||
|
@ -120,10 +120,12 @@ function MousePaint() {
|
|||
y: 10,
|
||||
z: 10
|
||||
},
|
||||
lineWidth: LINE_WIDTH
|
||||
lineWidth: LINE_WIDTH,
|
||||
lifetime: LINE_LIFETIME
|
||||
});
|
||||
points = [];
|
||||
if (point) {
|
||||
|
||||
points.push(point);
|
||||
path.push(point);
|
||||
}
|
||||
|
@ -133,22 +135,22 @@ function MousePaint() {
|
|||
|
||||
function mouseMoveEvent(event) {
|
||||
|
||||
if (!isDrawing) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE);
|
||||
var point = Vec3.sum(Camera.getPosition(), addVector);
|
||||
points.push(point);
|
||||
path.push(point);
|
||||
Entities.editEntity(line, {
|
||||
linePoints: points
|
||||
});
|
||||
Entities.editEntity(brush, {
|
||||
position: point
|
||||
});
|
||||
if (!isDrawing) {
|
||||
return;
|
||||
}
|
||||
|
||||
points.push(point);
|
||||
path.push(point);
|
||||
|
||||
if (points.length === MAX_POINTS_PER_LINE) {
|
||||
//We need to start a new line!
|
||||
|
@ -253,7 +255,6 @@ function HydraPaint() {
|
|||
var maxLineWidth = 10;
|
||||
var currentLineWidth = minLineWidth;
|
||||
var MIN_PAINT_TRIGGER_THRESHOLD = .01;
|
||||
var LINE_LIFETIME = 20;
|
||||
var COLOR_CHANGE_TIME_FACTOR = 0.1;
|
||||
|
||||
var RIGHT_BUTTON_1 = 7
|
||||
|
@ -330,7 +331,7 @@ function HydraPaint() {
|
|||
z: 10
|
||||
},
|
||||
lineWidth: 5,
|
||||
// lifetime: LINE_LIFETIME
|
||||
lifetime: LINE_LIFETIME
|
||||
});
|
||||
this.points = [];
|
||||
if (point) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
// Created by Seth Alves on May 15th
|
||||
// Modified by Eric Levin on June 4
|
||||
// Persist toolbar by HRS 6/11/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Provides a pointer with option to draw on surfaces
|
||||
|
@ -31,9 +32,16 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
|||
var screenSize = Controller.getViewportDimensions();
|
||||
|
||||
var userCanPoint = false;
|
||||
var pointerButton = Overlays.addOverlay("image", {
|
||||
x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
Script.include(["libraries/toolBars.js"]);
|
||||
const persistKey = "highfidelity.pointer.toolbar.position";
|
||||
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
|
||||
toolBar.save = function () {
|
||||
Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
|
||||
};
|
||||
var old = JSON.parse(Settings.getValue(persistKey) || '0');
|
||||
var pointerButton = toolBar.addOverlay("image", {
|
||||
x: old ? old[0] : screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING,
|
||||
y: old ? old[1] : screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png",
|
||||
|
@ -150,4 +158,4 @@ Script.scriptEnding.connect(cleanup);
|
|||
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
|
|
|
@ -140,7 +140,7 @@ target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
|||
# link required hifi libraries
|
||||
link_hifi_libraries(shared octree environment gpu model render fbx networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer ui)
|
||||
render-utils entities-renderer ui auto-updater)
|
||||
|
||||
add_dependency_external_projects(sdl2)
|
||||
|
||||
|
|
BIN
interface/resources/images/reticleLink.png
Normal file
BIN
interface/resources/images/reticleLink.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
BIN
interface/resources/images/reticleWhite.png
Normal file
BIN
interface/resources/images/reticleWhite.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
172
interface/resources/qml/UpdateDialog.qml
Normal file
172
interface/resources/qml/UpdateDialog.qml
Normal file
|
@ -0,0 +1,172 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import QtGraphicalEffects 1.0
|
||||
import "controls"
|
||||
import "styles"
|
||||
|
||||
DialogContainer {
|
||||
HifiConstants { id: hifi }
|
||||
id: root
|
||||
objectName: "UpdateDialog"
|
||||
implicitWidth: updateDialog.width
|
||||
implicitHeight: updateDialog.height
|
||||
x: parent ? parent.width / 2 - width / 2 : 0
|
||||
y: parent ? parent.height / 2 - height / 2 : 0
|
||||
|
||||
UpdateDialog {
|
||||
id: updateDialog
|
||||
|
||||
implicitWidth: backgroundRectangle.width
|
||||
implicitHeight: backgroundRectangle.height
|
||||
|
||||
readonly property int inputWidth: 500
|
||||
readonly property int inputHeight: 60
|
||||
readonly property int borderWidth: 30
|
||||
readonly property int closeMargin: 16
|
||||
readonly property int inputSpacing: 16
|
||||
readonly property int buttonWidth: 150
|
||||
readonly property int buttonHeight: 50
|
||||
readonly property int buttonRadius: 15
|
||||
|
||||
signal triggerBuildDownload
|
||||
signal closeUpdateDialog
|
||||
|
||||
Column {
|
||||
id: mainContent
|
||||
width: updateDialog.inputWidth
|
||||
spacing: updateDialog.inputSpacing
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: backgroundRectangle
|
||||
color: "#2c86b1"
|
||||
opacity: 0.85
|
||||
radius: updateDialog.closeMargin * 2
|
||||
|
||||
width: updateDialog.inputWidth + updateDialog.borderWidth * 2
|
||||
height: updateDialog.inputHeight * 6 + updateDialog.closeMargin * 2
|
||||
|
||||
Rectangle {
|
||||
id: dialogTitle
|
||||
width: updateDialog.inputWidth
|
||||
height: updateDialog.inputHeight
|
||||
radius: height / 2
|
||||
color: "#ebebeb"
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: updateDialog.inputSpacing
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
id: updateAvailableText
|
||||
text: "Update Available"
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
leftMargin: updateDialog.inputSpacing
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: updateDialog.updateAvailableDetails
|
||||
font.pixelSize: 14
|
||||
color: hifi.colors.text
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: updateAvailableText.right
|
||||
leftMargin: 13
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: scrollArea
|
||||
anchors {
|
||||
top: dialogTitle.bottom
|
||||
}
|
||||
contentWidth: updateDialog.inputWidth
|
||||
contentHeight: backgroundRectangle.height - (dialogTitle.height * 2.5)
|
||||
width: updateDialog.inputWidth
|
||||
height: backgroundRectangle.height - (dialogTitle.height * 2.5)
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
clip: true
|
||||
|
||||
TextEdit {
|
||||
id: releaseNotes
|
||||
wrapMode: TextEdit.Wrap
|
||||
width: parent.width
|
||||
readOnly: true
|
||||
text: updateDialog.releaseNotes
|
||||
font.pixelSize: 14
|
||||
color: hifi.colors.text
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: updateDialog.borderWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: downloadButton
|
||||
width: updateDialog.buttonWidth
|
||||
height: updateDialog.buttonHeight
|
||||
radius: updateDialog.buttonRadius
|
||||
color: "green"
|
||||
anchors {
|
||||
top: scrollArea.bottom
|
||||
topMargin: 10
|
||||
right: backgroundRectangle.right
|
||||
rightMargin: 15
|
||||
}
|
||||
Text {
|
||||
text: "Upgrade"
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: downloadButtonAction
|
||||
anchors.fill: parent
|
||||
onClicked: updateDialog.triggerUpgrade()
|
||||
cursorShape: "PointingHandCursor"
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: cancelButton
|
||||
width: updateDialog.buttonWidth
|
||||
height: updateDialog.buttonHeight
|
||||
radius: updateDialog.buttonRadius
|
||||
color: "red"
|
||||
anchors {
|
||||
top: scrollArea.bottom
|
||||
topMargin: 10
|
||||
right: downloadButton.left
|
||||
rightMargin: 15
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Cancel"
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: cancelButtonAction
|
||||
anchors.fill: parent
|
||||
onClicked: updateDialog.closeDialog()
|
||||
cursorShape: "PointingHandCursor"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
BIN
interface/resources/sounds/goodbye.wav
Normal file
BIN
interface/resources/sounds/goodbye.wav
Normal file
Binary file not shown.
BIN
interface/resources/sounds/hello.wav
Normal file
BIN
interface/resources/sounds/hello.wav
Normal file
Binary file not shown.
|
@ -57,8 +57,10 @@
|
|||
|
||||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <CursorManager.h>
|
||||
#include <AmbientOcclusionEffect.h>
|
||||
#include <AudioInjector.h>
|
||||
#include <AutoUpdater.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <EntityScriptingInterface.h>
|
||||
|
@ -146,6 +148,7 @@
|
|||
#include "ui/StandAloneJSConsole.h"
|
||||
#include "ui/Stats.h"
|
||||
#include "ui/AddressBarDialog.h"
|
||||
#include "ui/UpdateDialog.h"
|
||||
|
||||
|
||||
// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||
|
@ -294,6 +297,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
auto discoverabilityManager = DependencyManager::set<DiscoverabilityManager>();
|
||||
auto sceneScriptingInterface = DependencyManager::set<SceneScriptingInterface>();
|
||||
auto offscreenUi = DependencyManager::set<OffscreenUi>();
|
||||
auto autoUpdater = DependencyManager::set<AutoUpdater>();
|
||||
auto pathUtils = DependencyManager::set<PathUtils>();
|
||||
auto actionFactory = DependencyManager::set<InterfaceActionFactory>();
|
||||
|
||||
|
@ -423,6 +427,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
connect(audioIO.data(), &AudioClient::muteToggled, this, &Application::audioMuteToggled);
|
||||
connect(audioIO.data(), &AudioClient::receivedFirstPacket,
|
||||
&AudioScriptingInterface::getInstance(), &AudioScriptingInterface::receivedFirstPacket);
|
||||
connect(audioIO.data(), &AudioClient::disconnected,
|
||||
&AudioScriptingInterface::getInstance(), &AudioScriptingInterface::disconnected);
|
||||
|
||||
audioThread->start();
|
||||
|
||||
|
@ -559,8 +565,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
// allow you to move an entity around in your hand
|
||||
_entityEditSender.setPacketsPerSecond(3000); // super high!!
|
||||
|
||||
checkVersion();
|
||||
|
||||
_overlays.init(); // do this before scripts load
|
||||
|
||||
_runningScriptsWidget->setRunningScripts(getRunningScripts());
|
||||
|
@ -632,9 +636,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
ddeTracker->init();
|
||||
connect(ddeTracker.data(), &FaceTracker::muteToggled, this, &Application::faceTrackerMuteToggled);
|
||||
#endif
|
||||
|
||||
auto applicationUpdater = DependencyManager::get<AutoUpdater>();
|
||||
connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog);
|
||||
applicationUpdater->checkForUpdate();
|
||||
}
|
||||
|
||||
|
||||
void Application::aboutToQuit() {
|
||||
emit beforeAboutToQuit();
|
||||
|
||||
|
@ -824,6 +831,7 @@ void Application::initializeUi() {
|
|||
LoginDialog::registerType();
|
||||
MessageDialog::registerType();
|
||||
VrMenu::registerType();
|
||||
UpdateDialog::registerType();
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->create(_glWidget->context()->contextHandle());
|
||||
|
@ -955,12 +963,15 @@ void Application::paintGL() {
|
|||
displaySide(&renderArgs, _myCamera);
|
||||
glPopMatrix();
|
||||
|
||||
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
_rearMirrorTools->render(&renderArgs, true, _glWidget->mapFromGlobal(QCursor::pos()));
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
renderRearViewMirror(&renderArgs, _mirrorViewRect);
|
||||
}
|
||||
|
||||
renderArgs._renderMode = RenderArgs::NORMAL_RENDER_MODE;
|
||||
|
||||
auto finalFbo = DependencyManager::get<GlowEffect>()->render(&renderArgs);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
@ -1241,9 +1252,20 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Apostrophe:
|
||||
resetSensors();
|
||||
case Qt::Key_Apostrophe: {
|
||||
if (isMeta) {
|
||||
auto cursor = Cursor::Manager::instance().getCursor();
|
||||
auto curIcon = cursor->getIcon();
|
||||
if (curIcon == Cursor::Icon::DEFAULT) {
|
||||
cursor->setIcon(Cursor::Icon::LINK);
|
||||
} else {
|
||||
cursor->setIcon(Cursor::Icon::DEFAULT);
|
||||
}
|
||||
} else {
|
||||
resetSensors();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_A:
|
||||
if (isShifted) {
|
||||
|
@ -1367,12 +1389,27 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
case Qt::Key_Slash:
|
||||
Menu::getInstance()->triggerOption(MenuOption::Stats);
|
||||
break;
|
||||
case Qt::Key_Plus:
|
||||
_myAvatar->increaseSize();
|
||||
|
||||
case Qt::Key_Plus: {
|
||||
if (isMeta && event->modifiers().testFlag(Qt::KeypadModifier)) {
|
||||
auto& cursorManager = Cursor::Manager::instance();
|
||||
cursorManager.setScale(cursorManager.getScale() * 1.1f);
|
||||
} else {
|
||||
_myAvatar->increaseSize();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Minus:
|
||||
_myAvatar->decreaseSize();
|
||||
}
|
||||
|
||||
case Qt::Key_Minus: {
|
||||
if (isMeta && event->modifiers().testFlag(Qt::KeypadModifier)) {
|
||||
auto& cursorManager = Cursor::Manager::instance();
|
||||
cursorManager.setScale(cursorManager.getScale() / 1.1f);
|
||||
} else {
|
||||
_myAvatar->decreaseSize();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_Equal:
|
||||
_myAvatar->resetSize();
|
||||
break;
|
||||
|
@ -3231,6 +3268,9 @@ namespace render {
|
|||
template <> const Item::Bound payloadGetBound(const BackgroundRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||
template <> void payloadRender(const BackgroundRenderData::Pointer& background, RenderArgs* args) {
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
// Background rendering decision
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
auto skybox = model::SkyboxPointer();
|
||||
|
@ -3298,7 +3338,8 @@ namespace render {
|
|||
PerformanceTimer perfTimer("atmosphere");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... atmosphere...");
|
||||
background->_environment->renderAtmospheres(*(args->_viewFrustum));
|
||||
|
||||
background->_environment->renderAtmospheres(batch, *(args->_viewFrustum));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3307,13 +3348,13 @@ namespace render {
|
|||
|
||||
skybox = skyStage->getSkybox();
|
||||
if (skybox) {
|
||||
gpu::Batch batch;
|
||||
model::Skybox::render(batch, *(Application::getInstance()->getDisplayViewFrustum()), *skybox);
|
||||
|
||||
gpu::GLBackend::renderBatch(batch, true);
|
||||
glUseProgram(0);
|
||||
}
|
||||
}
|
||||
// FIX ME - If I don't call this renderBatch() here, then the atmosphere and skybox don't render, but it
|
||||
// seems like these payloadRender() methods shouldn't be doing this. We need to investigate why the engine
|
||||
// isn't rendering our batch
|
||||
gpu::GLBackend::renderBatch(batch, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3419,7 +3460,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
"Application::displaySide() ... entities...");
|
||||
|
||||
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
|
||||
RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) {
|
||||
renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_HULLS);
|
||||
|
@ -3428,10 +3468,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
renderDebugFlags =
|
||||
(RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP);
|
||||
}
|
||||
if (theCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
||||
}
|
||||
renderArgs->_renderMode = renderMode;
|
||||
renderArgs->_debugFlags = renderDebugFlags;
|
||||
_entities.render(renderArgs);
|
||||
}
|
||||
|
@ -4503,72 +4539,6 @@ void Application::toggleLogDialog() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::checkVersion() {
|
||||
QNetworkRequest latestVersionRequest((QUrl(CHECK_VERSION_URL)));
|
||||
latestVersionRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
latestVersionRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().get(latestVersionRequest);
|
||||
connect(reply, SIGNAL(finished()), SLOT(parseVersionXml()));
|
||||
}
|
||||
|
||||
void Application::parseVersionXml() {
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
QString operatingSystem("win");
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QString operatingSystem("mac");
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
QString operatingSystem("ubuntu");
|
||||
#endif
|
||||
|
||||
QString latestVersion;
|
||||
QUrl downloadUrl;
|
||||
QString releaseNotes("Unavailable");
|
||||
QNetworkReply* sender = qobject_cast<QNetworkReply*>(QObject::sender());
|
||||
|
||||
QXmlStreamReader xml(sender);
|
||||
|
||||
while (!xml.atEnd() && !xml.hasError()) {
|
||||
if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == operatingSystem) {
|
||||
while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == operatingSystem)) {
|
||||
if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "version") {
|
||||
xml.readNext();
|
||||
latestVersion = xml.text().toString();
|
||||
}
|
||||
if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "url") {
|
||||
xml.readNext();
|
||||
downloadUrl = QUrl(xml.text().toString());
|
||||
}
|
||||
xml.readNext();
|
||||
}
|
||||
}
|
||||
xml.readNext();
|
||||
}
|
||||
|
||||
if (!shouldSkipVersion(latestVersion) && applicationVersion() != latestVersion) {
|
||||
new UpdateDialog(_glWidget, releaseNotes, latestVersion, downloadUrl);
|
||||
}
|
||||
sender->deleteLater();
|
||||
}
|
||||
|
||||
bool Application::shouldSkipVersion(QString latestVersion) {
|
||||
QFile skipFile(SKIP_FILENAME);
|
||||
skipFile.open(QIODevice::ReadWrite);
|
||||
QString skipVersion(skipFile.readAll());
|
||||
return (skipVersion == latestVersion || applicationVersion() == "dev");
|
||||
}
|
||||
|
||||
void Application::skipVersion(QString latestVersion) {
|
||||
QFile skipFile(SKIP_FILENAME);
|
||||
skipFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||||
skipFile.seek(0);
|
||||
skipFile.write(latestVersion.toStdString().c_str());
|
||||
}
|
||||
|
||||
void Application::takeSnapshot() {
|
||||
QMediaPlayer* player = new QMediaPlayer();
|
||||
QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav");
|
||||
|
|
|
@ -66,7 +66,6 @@
|
|||
#include "ui/SnapshotShareDialog.h"
|
||||
#include "ui/LodToolsDialog.h"
|
||||
#include "ui/LogDialog.h"
|
||||
#include "ui/UpdateDialog.h"
|
||||
#include "ui/overlays/Overlays.h"
|
||||
#include "ui/ApplicationOverlay.h"
|
||||
#include "ui/RunningScriptsWidget.h"
|
||||
|
@ -312,8 +311,6 @@ public:
|
|||
|
||||
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
|
||||
|
||||
void skipVersion(QString latestVersion);
|
||||
|
||||
QStringList getRunningScripts() { return _scriptEnginesHash.keys(); }
|
||||
ScriptEngine* getScriptEngine(QString scriptHash) { return _scriptEnginesHash.contains(scriptHash) ? _scriptEnginesHash[scriptHash] : NULL; }
|
||||
|
||||
|
@ -460,8 +457,6 @@ private slots:
|
|||
void restoreMirrorView();
|
||||
void shrinkMirrorView();
|
||||
|
||||
void parseVersionXml();
|
||||
|
||||
void manageRunningScriptsWidgetVisibility(bool shown);
|
||||
|
||||
void runTests();
|
||||
|
@ -627,9 +622,6 @@ private:
|
|||
|
||||
FileLogger* _logger;
|
||||
|
||||
void checkVersion();
|
||||
void displayUpdateDialog();
|
||||
bool shouldSkipVersion(QString latestVersion);
|
||||
void takeSnapshot();
|
||||
|
||||
TouchEvent _lastTouchEvent;
|
||||
|
|
|
@ -90,6 +90,30 @@ Menu::Menu() {
|
|||
addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J,
|
||||
qApp, SLOT(toggleRunningScriptsWidget()));
|
||||
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
|
||||
addDisabledActionAndSeparator(fileMenu, "History");
|
||||
|
||||
QAction* backAction = addActionToQMenuAndActionHash(fileMenu,
|
||||
MenuOption::Back,
|
||||
0,
|
||||
addressManager.data(),
|
||||
SLOT(goBack()));
|
||||
|
||||
QAction* forwardAction = addActionToQMenuAndActionHash(fileMenu,
|
||||
MenuOption::Forward,
|
||||
0,
|
||||
addressManager.data(),
|
||||
SLOT(goForward()));
|
||||
|
||||
// connect to the AddressManager signal to enable and disable the back and forward menu items
|
||||
connect(addressManager.data(), &AddressManager::goBackPossible, backAction, &QAction::setEnabled);
|
||||
connect(addressManager.data(), &AddressManager::goForwardPossible, forwardAction, &QAction::setEnabled);
|
||||
|
||||
// set the two actions to start disabled since the stacks are clear on startup
|
||||
backAction->setDisabled(true);
|
||||
forwardAction->setDisabled(true);
|
||||
|
||||
addDisabledActionAndSeparator(fileMenu, "Location");
|
||||
qApp->getBookmarks()->setupMenus(this, fileMenu);
|
||||
|
||||
|
@ -98,7 +122,6 @@ Menu::Menu() {
|
|||
Qt::CTRL | Qt::Key_L,
|
||||
dialogsManager.data(),
|
||||
SLOT(toggleAddressBar()));
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyAddress, 0,
|
||||
addressManager.data(), SLOT(copyAddress()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyPath, 0,
|
||||
|
@ -407,7 +430,7 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::MuteFaceTracking,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_F, true, // DDE face tracking is on by default
|
||||
qApp, SLOT(toggleFaceTrackerMute()));
|
||||
addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::AutoMuteAudio, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::AutoMuteAudio, 0, false);
|
||||
#endif
|
||||
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
|
|
|
@ -149,6 +149,7 @@ namespace MenuOption {
|
|||
const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams";
|
||||
const QString AutoMuteAudio = "Auto Mute Microphone";
|
||||
const QString AvatarReceiveStats = "Show Receive Stats";
|
||||
const QString Back = "Back";
|
||||
const QString BandwidthDetails = "Bandwidth Details";
|
||||
const QString BinaryEyelidControl = "Binary Eyelid Control";
|
||||
const QString BlueSpeechSphere = "Blue Sphere While Speaking";
|
||||
|
@ -194,12 +195,12 @@ namespace MenuOption {
|
|||
const QString Faceshift = "Faceshift";
|
||||
const QString FilterSixense = "Smooth Sixense Movement";
|
||||
const QString FirstPerson = "First Person";
|
||||
const QString Forward = "Forward";
|
||||
const QString FrameTimer = "Show Timer";
|
||||
const QString Fullscreen = "Fullscreen";
|
||||
const QString FullscreenMirror = "Fullscreen Mirror";
|
||||
const QString GlowWhenSpeaking = "Glow When Speaking";
|
||||
const QString NamesAboveHeads = "Names Above Heads";
|
||||
const QString GoToUser = "Go To User";
|
||||
const QString HMDTools = "HMD Tools";
|
||||
const QString IncreaseAvatarSize = "Increase Avatar Size";
|
||||
const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
|
||||
|
|
|
@ -328,6 +328,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo
|
|||
if (postLighting &&
|
||||
glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), _position) < 10.0f) {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
auto deferredLighting = DependencyManager::get<DeferredLightingEffect>();
|
||||
|
||||
// render pointing lasers
|
||||
glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f);
|
||||
|
@ -354,6 +355,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo
|
|||
pointerTransform.setTranslation(position);
|
||||
pointerTransform.setRotation(rotation);
|
||||
batch->setModelTransform(pointerTransform);
|
||||
deferredLighting->bindSimpleProgram(*batch);
|
||||
geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
|
||||
}
|
||||
}
|
||||
|
@ -376,6 +378,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo
|
|||
pointerTransform.setTranslation(position);
|
||||
pointerTransform.setRotation(rotation);
|
||||
batch->setModelTransform(pointerTransform);
|
||||
deferredLighting->bindSimpleProgram(*batch);
|
||||
geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
|
||||
}
|
||||
}
|
||||
|
@ -462,7 +465,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo
|
|||
Transform transform;
|
||||
transform.setTranslation(position);
|
||||
batch->setModelTransform(transform);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(*batch, LOOK_AT_INDICATOR_RADIUS, 15, 15, LOOK_AT_INDICATOR_COLOR);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(*batch, LOOK_AT_INDICATOR_RADIUS
|
||||
, 15, 15, LOOK_AT_INDICATOR_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -494,6 +498,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo
|
|||
_voiceSphereID = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(*batch, sphereRadius, 15, 15,
|
||||
glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true,
|
||||
_voiceSphereID);
|
||||
|
|
|
@ -143,7 +143,6 @@ ApplicationOverlay::ApplicationOverlay() :
|
|||
_alpha(1.0f),
|
||||
_oculusUIRadius(1.0f),
|
||||
_trailingAudioLoudness(0.0f),
|
||||
_crosshairTexture(0),
|
||||
_previousBorderWidth(-1),
|
||||
_previousBorderHeight(-1),
|
||||
_previousMagnifierBottomLeft(),
|
||||
|
@ -591,8 +590,8 @@ void ApplicationOverlay::renderPointers() {
|
|||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
|
||||
//glActiveTexture(GL_TEXTURE0);
|
||||
//bindCursorTexture();
|
||||
|
||||
if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) {
|
||||
//If we are in oculus, render reticle later
|
||||
|
@ -637,8 +636,8 @@ void ApplicationOverlay::renderPointers() {
|
|||
_magActive[MOUSE] = false;
|
||||
renderControllerPointers();
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
//glBindTexture(GL_TEXTURE_2D, 0);
|
||||
//glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderControllerPointers() {
|
||||
|
|
|
@ -96,7 +96,6 @@ private:
|
|||
};
|
||||
|
||||
float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE;
|
||||
|
||||
void renderReticle(glm::quat orientation, float alpha);
|
||||
void renderPointers();;
|
||||
void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder);
|
||||
|
@ -108,6 +107,7 @@ private:
|
|||
void renderCameraToggle();
|
||||
void renderStatsAndLogs();
|
||||
void renderDomainConnectionStatusBorder();
|
||||
void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
|
||||
|
||||
TexturedHemisphere _overlays;
|
||||
|
||||
|
@ -125,9 +125,12 @@ private:
|
|||
float _alpha = 1.0f;
|
||||
float _oculusUIRadius;
|
||||
float _trailingAudioLoudness;
|
||||
|
||||
gpu::TexturePointer _crosshairTexture;
|
||||
|
||||
|
||||
gpu::TexturePointer _crosshairTexture;
|
||||
QMap<uint16_t, gpu::TexturePointer> _cursors;
|
||||
|
||||
GLuint _newUiTexture{ 0 };
|
||||
|
||||
int _reticleQuad;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "OctreeStatsDialog.h"
|
||||
#include "PreferencesDialog.h"
|
||||
#include "ScriptEditorWindow.h"
|
||||
#include "UpdateDialog.h"
|
||||
|
||||
|
||||
void DialogsManager::toggleAddressBar() {
|
||||
|
@ -50,6 +51,10 @@ void DialogsManager::showLoginDialog() {
|
|||
LoginDialog::show();
|
||||
}
|
||||
|
||||
void DialogsManager::showUpdateDialog() {
|
||||
UpdateDialog::show();
|
||||
}
|
||||
|
||||
void DialogsManager::octreeStatsDetails() {
|
||||
if (!_octreeStatsDialog) {
|
||||
_octreeStatsDialog = new OctreeStatsDialog(qApp->getWindow(), qApp->getOcteeSceneStats());
|
||||
|
|
|
@ -35,6 +35,7 @@ class ScriptEditorWindow;
|
|||
class QMessageBox;
|
||||
class AvatarAppearanceDialog;
|
||||
class DomainConnectionDialog;
|
||||
class UpdateDialog;
|
||||
|
||||
class DialogsManager : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -64,6 +65,9 @@ public slots:
|
|||
void showIRCLink();
|
||||
void changeAvatarAppearance();
|
||||
void showDomainConnectionDialog();
|
||||
|
||||
// Application Update
|
||||
void showUpdateDialog();
|
||||
|
||||
private slots:
|
||||
void toggleToolWindow();
|
||||
|
@ -101,6 +105,7 @@ private:
|
|||
QPointer<ScriptEditorWindow> _scriptEditor;
|
||||
QPointer<AvatarAppearanceDialog> _avatarAppearanceDialog;
|
||||
QPointer<DomainConnectionDialog> _domainConnectionDialog;
|
||||
QPointer<UpdateDialog> _updateDialog;
|
||||
};
|
||||
|
||||
#endif // hifi_DialogsManager_h
|
||||
|
|
|
@ -161,6 +161,10 @@ void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int heigh
|
|||
((rgba >> 8) & 0xff) / 255.0f,
|
||||
(rgba & 0xff) / 255.0f);
|
||||
|
||||
// FIX ME: is this correct? It seems to work to fix textures bleeding into us...
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(x, y, width, height, color);
|
||||
}
|
||||
|
||||
|
@ -460,7 +464,7 @@ void Stats::display(
|
|||
verticalOffset = STATS_PELS_INITIALOFFSET;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3;
|
||||
|
||||
lines = _expanded ? 10 : 2;
|
||||
lines = _expanded ? 10 : 3;
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, canvasSize.x - horizontalOffset,
|
||||
(lines + 1) * STATS_PELS_PER_LINE);
|
||||
|
@ -608,12 +612,10 @@ void Stats::display(
|
|||
}
|
||||
|
||||
// LOD Details
|
||||
if (_expanded) {
|
||||
octreeStats.str("");
|
||||
QString displayLODDetails = DependencyManager::get<LODManager>()->getLODFeedbackText();
|
||||
octreeStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed());
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||
}
|
||||
octreeStats.str("");
|
||||
QString displayLODDetails = DependencyManager::get<LODManager>()->getLODFeedbackText();
|
||||
octreeStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed());
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,54 +2,50 @@
|
|||
// UpdateDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Created by Leonardo Murillo on 6/3/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include <QDesktopServices>
|
||||
|
||||
#include "ui_updateDialog.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "UpdateDialog.h"
|
||||
|
||||
#include <AutoUpdater.h>
|
||||
|
||||
UpdateDialog::UpdateDialog(QWidget *parent, const QString& releaseNotes, const QString& latestVersion, const QUrl& downloadURL) :
|
||||
QDialog(parent),
|
||||
_latestVersion(latestVersion),
|
||||
_downloadUrl(downloadURL)
|
||||
#include "DependencyManager.h"
|
||||
|
||||
HIFI_QML_DEF(UpdateDialog)
|
||||
|
||||
UpdateDialog::UpdateDialog(QQuickItem* parent) :
|
||||
OffscreenQmlDialog(parent)
|
||||
{
|
||||
Ui::Dialog dialogUI;
|
||||
dialogUI.setupUi(this);
|
||||
|
||||
QString updateRequired = QString("You are currently running build %1, the latest build released is %2."
|
||||
"\n\nPlease download and install the most recent release to access the latest features and bug fixes.")
|
||||
.arg(Application::getInstance()->applicationVersion(), latestVersion);
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QPushButton* downloadButton = findChild<QPushButton*>("downloadButton");
|
||||
QPushButton* skipButton = findChild<QPushButton*>("skipButton");
|
||||
QPushButton* closeButton = findChild<QPushButton*>("closeButton");
|
||||
QLabel* updateContent = findChild<QLabel*>("updateContent");
|
||||
|
||||
updateContent->setText(updateRequired);
|
||||
|
||||
connect(downloadButton, SIGNAL(released()), this, SLOT(handleDownload()));
|
||||
connect(skipButton, SIGNAL(released()), this, SLOT(handleSkip()));
|
||||
connect(closeButton, SIGNAL(released()), this, SLOT(close()));
|
||||
|
||||
QMetaObject::invokeMethod(this, "show", Qt::QueuedConnection);
|
||||
auto applicationUpdater = DependencyManager::get<AutoUpdater>();
|
||||
int currentVersion = QCoreApplication::applicationVersion().toInt();
|
||||
int latestVersion = applicationUpdater.data()->getBuildData().lastKey();
|
||||
int versionsBehind = latestVersion - currentVersion;
|
||||
_updateAvailableDetails = "v" + QString::number(latestVersion) + " released on " + applicationUpdater.data()->getBuildData()[latestVersion]["releaseTime"];
|
||||
_updateAvailableDetails += "\nYou are " + QString::number(versionsBehind) + " versions behind";
|
||||
_releaseNotes = applicationUpdater.data()->getBuildData()[latestVersion]["releaseNotes"];
|
||||
}
|
||||
|
||||
void UpdateDialog::handleDownload() {
|
||||
QDesktopServices::openUrl(_downloadUrl);
|
||||
Application::getInstance()->quit();
|
||||
const QString& UpdateDialog::updateAvailableDetails() const {
|
||||
return _updateAvailableDetails;
|
||||
}
|
||||
|
||||
void UpdateDialog::handleSkip() {
|
||||
Application::getInstance()->skipVersion(_latestVersion);
|
||||
this->close();
|
||||
const QString& UpdateDialog::releaseNotes() const {
|
||||
return _releaseNotes;
|
||||
}
|
||||
|
||||
void UpdateDialog::closeDialog() {
|
||||
hide();
|
||||
}
|
||||
|
||||
void UpdateDialog::hide() {
|
||||
((QQuickItem*)parent())->setEnabled(false);
|
||||
}
|
||||
|
||||
void UpdateDialog::triggerUpgrade() {
|
||||
auto applicationUpdater = DependencyManager::get<AutoUpdater>();
|
||||
applicationUpdater.data()->performAutoUpdate(applicationUpdater.data()->getBuildData().lastKey());
|
||||
}
|
|
@ -2,30 +2,42 @@
|
|||
// UpdateDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Created by Leonardo Murillo on 6/3/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_UpdateDialog_h
|
||||
#define hifi_UpdateDialog_h
|
||||
|
||||
#include <QWidget>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
class UpdateDialog : public QDialog {
|
||||
#include <OffscreenQmlDialog.h>
|
||||
|
||||
class UpdateDialog : public OffscreenQmlDialog {
|
||||
Q_OBJECT
|
||||
HIFI_QML_DECL
|
||||
|
||||
Q_PROPERTY(QString updateAvailableDetails READ updateAvailableDetails)
|
||||
Q_PROPERTY(QString releaseNotes READ releaseNotes)
|
||||
|
||||
public:
|
||||
UpdateDialog(QWidget* parent, const QString& releaseNotes, const QString& latestVersion, const QUrl& downloadURL);
|
||||
UpdateDialog(QQuickItem* parent = nullptr);
|
||||
const QString& updateAvailableDetails() const;
|
||||
const QString& releaseNotes() const;
|
||||
|
||||
private:
|
||||
QString _latestVersion;
|
||||
QUrl _downloadUrl;
|
||||
|
||||
private slots:
|
||||
void handleDownload();
|
||||
void handleSkip();
|
||||
QString _updateAvailableDetails;
|
||||
QString _releaseNotes;
|
||||
|
||||
protected:
|
||||
void hide();
|
||||
Q_INVOKABLE void triggerUpgrade();
|
||||
Q_INVOKABLE void closeDialog();
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_UpdateDialog_h
|
||||
|
|
|
@ -43,72 +43,90 @@ void BillboardOverlay::render(RenderArgs* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.5f);
|
||||
glm::quat rotation;
|
||||
if (_isFacingAvatar) {
|
||||
// rotate about vertical to face the camera
|
||||
rotation = Application::getInstance()->getCamera()->getRotation();
|
||||
rotation *= glm::angleAxis(glm::pi<float>(), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
rotation *= getRotation();
|
||||
} else {
|
||||
rotation = getRotation();
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
float imageWidth = _texture->getWidth();
|
||||
float imageHeight = _texture->getHeight();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _texture->getID());
|
||||
QRect fromImage;
|
||||
if (_fromImage.isNull()) {
|
||||
fromImage.setX(0);
|
||||
fromImage.setY(0);
|
||||
fromImage.setWidth(imageWidth);
|
||||
fromImage.setHeight(imageHeight);
|
||||
} else {
|
||||
float scaleX = imageWidth / _texture->getOriginalWidth();
|
||||
float scaleY = imageHeight / _texture->getOriginalHeight();
|
||||
|
||||
glPushMatrix(); {
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
glm::quat rotation;
|
||||
if (_isFacingAvatar) {
|
||||
// rotate about vertical to face the camera
|
||||
rotation = Application::getInstance()->getCamera()->getRotation();
|
||||
rotation *= glm::angleAxis(glm::pi<float>(), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
rotation *= getRotation();
|
||||
} else {
|
||||
rotation = getRotation();
|
||||
}
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glScalef(_scale, _scale, _scale);
|
||||
fromImage.setX(scaleX * _fromImage.x());
|
||||
fromImage.setY(scaleY * _fromImage.y());
|
||||
fromImage.setWidth(scaleX * _fromImage.width());
|
||||
fromImage.setHeight(scaleY * _fromImage.height());
|
||||
}
|
||||
|
||||
const float MAX_COLOR = 255.0f;
|
||||
xColor color = getColor();
|
||||
float alpha = getAlpha();
|
||||
float maxSize = glm::max(fromImage.width(), fromImage.height());
|
||||
float x = fromImage.width() / (2.0f * maxSize);
|
||||
float y = -fromImage.height() / (2.0f * maxSize);
|
||||
|
||||
float imageWidth = _texture->getWidth();
|
||||
float imageHeight = _texture->getHeight();
|
||||
glm::vec2 topLeft(-x, -y);
|
||||
glm::vec2 bottomRight(x, y);
|
||||
glm::vec2 texCoordTopLeft(fromImage.x() / imageWidth, fromImage.y() / imageHeight);
|
||||
glm::vec2 texCoordBottomRight((fromImage.x() + fromImage.width()) / imageWidth,
|
||||
(fromImage.y() + fromImage.height()) / imageHeight);
|
||||
|
||||
QRect fromImage;
|
||||
if (_fromImage.isNull()) {
|
||||
fromImage.setX(0);
|
||||
fromImage.setY(0);
|
||||
fromImage.setWidth(imageWidth);
|
||||
fromImage.setHeight(imageHeight);
|
||||
} else {
|
||||
float scaleX = imageWidth / _texture->getOriginalWidth();
|
||||
float scaleY = imageHeight / _texture->getOriginalHeight();
|
||||
const float MAX_COLOR = 255.0f;
|
||||
xColor color = getColor();
|
||||
float alpha = getAlpha();
|
||||
|
||||
fromImage.setX(scaleX * _fromImage.x());
|
||||
fromImage.setY(scaleY * _fromImage.y());
|
||||
fromImage.setWidth(scaleX * _fromImage.width());
|
||||
fromImage.setHeight(scaleY * _fromImage.height());
|
||||
}
|
||||
auto batch = args->_batch;
|
||||
|
||||
float maxSize = glm::max(fromImage.width(), fromImage.height());
|
||||
float x = fromImage.width() / (2.0f * maxSize);
|
||||
float y = -fromImage.height() / (2.0f * maxSize);
|
||||
if (batch) {
|
||||
Transform transform;
|
||||
transform.setTranslation(_position);
|
||||
transform.setRotation(rotation);
|
||||
transform.setScale(_scale);
|
||||
|
||||
glm::vec2 topLeft(-x, -y);
|
||||
glm::vec2 bottomRight(x, y);
|
||||
glm::vec2 texCoordTopLeft(fromImage.x() / imageWidth, fromImage.y() / imageHeight);
|
||||
glm::vec2 texCoordBottomRight((fromImage.x() + fromImage.width()) / imageWidth,
|
||||
(fromImage.y() + fromImage.height()) / imageHeight);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
batch->setModelTransform(transform);
|
||||
batch->setUniformTexture(0, _texture->getGPUTexture());
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(*batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha));
|
||||
|
||||
batch->setUniformTexture(0, args->_whiteTexture); // restore default white color after me
|
||||
} else {
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.5f);
|
||||
|
||||
} glPopMatrix();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_LIGHTING);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glBindTexture(GL_TEXTURE_2D, _texture->getID());
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glPushMatrix(); {
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glScalef(_scale, _scale, _scale);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha));
|
||||
|
||||
} glPopMatrix();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_LIGHTING);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
||||
|
|
|
@ -35,13 +35,6 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
return; // do nothing if we're not visible
|
||||
}
|
||||
|
||||
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
|
||||
float alpha = getAlpha();
|
||||
xColor color = getColor();
|
||||
const float MAX_COLOR = 255.0f;
|
||||
|
@ -49,91 +42,161 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
|
||||
//glDisable(GL_LIGHTING);
|
||||
|
||||
// TODO: handle registration point??
|
||||
// TODO: handle registration point??
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 center = getCenter();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
if (_isSolid) {
|
||||
if (_borderSize > 0) {
|
||||
// Draw a cube at a larger size behind the main cube, creating
|
||||
// a border effect.
|
||||
// Disable writing to the depth mask so that the "border" cube will not
|
||||
// occlude the main cube. This means the border could be covered by
|
||||
// overlays that are further back and drawn later, but this is good
|
||||
// enough for the use-case.
|
||||
glDepthMask(GL_FALSE);
|
||||
glPushMatrix();
|
||||
glScalef(dimensions.x * _borderSize, dimensions.y * _borderSize, dimensions.z * _borderSize);
|
||||
|
||||
if (_drawOnHUD) {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
}
|
||||
auto batch = args->_batch;
|
||||
|
||||
glPopMatrix();
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
if (batch) {
|
||||
Transform transform;
|
||||
transform.setTranslation(position);
|
||||
transform.setRotation(rotation);
|
||||
if (_isSolid) {
|
||||
// if (_borderSize > 0) {
|
||||
// // Draw a cube at a larger size behind the main cube, creating
|
||||
// // a border effect.
|
||||
// // Disable writing to the depth mask so that the "border" cube will not
|
||||
// // occlude the main cube. This means the border could be covered by
|
||||
// // overlays that are further back and drawn later, but this is good
|
||||
// // enough for the use-case.
|
||||
// transform.setScale(dimensions * _borderSize);
|
||||
// batch->setModelTransform(transform);
|
||||
// DependencyManager::get<GeometryCache>()->renderSolidCube(*batch, 1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
// }
|
||||
|
||||
transform.setScale(dimensions);
|
||||
batch->setModelTransform(transform);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(*batch, 1.0f, cubeColor);
|
||||
} else {
|
||||
|
||||
if (getIsDashedLine()) {
|
||||
transform.setScale(1.0f);
|
||||
batch->setModelTransform(transform);
|
||||
|
||||
glm::vec3 halfDimensions = dimensions / 2.0f;
|
||||
glm::vec3 bottomLeftNear(-halfDimensions.x, -halfDimensions.y, -halfDimensions.z);
|
||||
glm::vec3 bottomRightNear(halfDimensions.x, -halfDimensions.y, -halfDimensions.z);
|
||||
glm::vec3 topLeftNear(-halfDimensions.x, halfDimensions.y, -halfDimensions.z);
|
||||
glm::vec3 topRightNear(halfDimensions.x, halfDimensions.y, -halfDimensions.z);
|
||||
|
||||
glm::vec3 bottomLeftFar(-halfDimensions.x, -halfDimensions.y, halfDimensions.z);
|
||||
glm::vec3 bottomRightFar(halfDimensions.x, -halfDimensions.y, halfDimensions.z);
|
||||
glm::vec3 topLeftFar(-halfDimensions.x, halfDimensions.y, halfDimensions.z);
|
||||
glm::vec3 topRightFar(halfDimensions.x, halfDimensions.y, halfDimensions.z);
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftNear, bottomRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightNear, bottomRightFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightFar, bottomLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftFar, bottomLeftNear, cubeColor);
|
||||
|
||||
geometryCache->renderDashedLine(*batch, topLeftNear, topRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, topRightNear, topRightFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, topRightFar, topLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, topLeftFar, topLeftNear, cubeColor);
|
||||
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftNear, topLeftNear, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightNear, topRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftFar, topLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightFar, topRightFar, cubeColor);
|
||||
|
||||
glPushMatrix();
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
if (_drawOnHUD) {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
} else {
|
||||
glLineWidth(_lineWidth);
|
||||
|
||||
if (getIsDashedLine()) {
|
||||
glm::vec3 halfDimensions = dimensions / 2.0f;
|
||||
glm::vec3 bottomLeftNear(-halfDimensions.x, -halfDimensions.y, -halfDimensions.z);
|
||||
glm::vec3 bottomRightNear(halfDimensions.x, -halfDimensions.y, -halfDimensions.z);
|
||||
glm::vec3 topLeftNear(-halfDimensions.x, halfDimensions.y, -halfDimensions.z);
|
||||
glm::vec3 topRightNear(halfDimensions.x, halfDimensions.y, -halfDimensions.z);
|
||||
|
||||
glm::vec3 bottomLeftFar(-halfDimensions.x, -halfDimensions.y, halfDimensions.z);
|
||||
glm::vec3 bottomRightFar(halfDimensions.x, -halfDimensions.y, halfDimensions.z);
|
||||
glm::vec3 topLeftFar(-halfDimensions.x, halfDimensions.y, halfDimensions.z);
|
||||
glm::vec3 topRightFar(halfDimensions.x, halfDimensions.y, halfDimensions.z);
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
geometryCache->renderDashedLine(bottomLeftNear, bottomRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomRightNear, bottomRightFar, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomRightFar, bottomLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomLeftFar, bottomLeftNear, cubeColor);
|
||||
|
||||
geometryCache->renderDashedLine(topLeftNear, topRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(topRightNear, topRightFar, cubeColor);
|
||||
geometryCache->renderDashedLine(topRightFar, topLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(topLeftFar, topLeftNear, cubeColor);
|
||||
|
||||
geometryCache->renderDashedLine(bottomLeftNear, topLeftNear, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomRightNear, topRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomLeftFar, topLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomRightFar, topRightFar, cubeColor);
|
||||
|
||||
} else {
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<GeometryCache>()->renderWireCube(1.0f, cubeColor);
|
||||
}
|
||||
transform.setScale(dimensions);
|
||||
batch->setModelTransform(transform);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(*batch, 1.0f, cubeColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
}
|
||||
} else {
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
if (_isSolid) {
|
||||
if (_borderSize > 0) {
|
||||
// Draw a cube at a larger size behind the main cube, creating
|
||||
// a border effect.
|
||||
// Disable writing to the depth mask so that the "border" cube will not
|
||||
// occlude the main cube. This means the border could be covered by
|
||||
// overlays that are further back and drawn later, but this is good
|
||||
// enough for the use-case.
|
||||
glDepthMask(GL_FALSE);
|
||||
glPushMatrix();
|
||||
glScalef(dimensions.x * _borderSize, dimensions.y * _borderSize, dimensions.z * _borderSize);
|
||||
|
||||
if (_drawOnHUD) {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
if (_drawOnHUD) {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
} else {
|
||||
glLineWidth(_lineWidth);
|
||||
|
||||
if (getIsDashedLine()) {
|
||||
glm::vec3 halfDimensions = dimensions / 2.0f;
|
||||
glm::vec3 bottomLeftNear(-halfDimensions.x, -halfDimensions.y, -halfDimensions.z);
|
||||
glm::vec3 bottomRightNear(halfDimensions.x, -halfDimensions.y, -halfDimensions.z);
|
||||
glm::vec3 topLeftNear(-halfDimensions.x, halfDimensions.y, -halfDimensions.z);
|
||||
glm::vec3 topRightNear(halfDimensions.x, halfDimensions.y, -halfDimensions.z);
|
||||
|
||||
glm::vec3 bottomLeftFar(-halfDimensions.x, -halfDimensions.y, halfDimensions.z);
|
||||
glm::vec3 bottomRightFar(halfDimensions.x, -halfDimensions.y, halfDimensions.z);
|
||||
glm::vec3 topLeftFar(-halfDimensions.x, halfDimensions.y, halfDimensions.z);
|
||||
glm::vec3 topRightFar(halfDimensions.x, halfDimensions.y, halfDimensions.z);
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
geometryCache->renderDashedLine(bottomLeftNear, bottomRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomRightNear, bottomRightFar, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomRightFar, bottomLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomLeftFar, bottomLeftNear, cubeColor);
|
||||
|
||||
geometryCache->renderDashedLine(topLeftNear, topRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(topRightNear, topRightFar, cubeColor);
|
||||
geometryCache->renderDashedLine(topRightFar, topLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(topLeftFar, topLeftNear, cubeColor);
|
||||
|
||||
geometryCache->renderDashedLine(bottomLeftNear, topLeftNear, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomRightNear, topRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomLeftFar, topLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(bottomRightFar, topRightFar, cubeColor);
|
||||
|
||||
} else {
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<GeometryCache>()->renderWireCube(1.0f, cubeColor);
|
||||
}
|
||||
}
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,87 +36,128 @@ void Grid3DOverlay::render(RenderArgs* args) {
|
|||
return; // do nothing if we're not visible
|
||||
}
|
||||
|
||||
if (!_gridProgram.isLinked()) {
|
||||
if (!_gridProgram.addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/grid.vert")) {
|
||||
qDebug() << "Failed to compile: " + _gridProgram.log();
|
||||
return;
|
||||
}
|
||||
if (!_gridProgram.addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/grid.frag")) {
|
||||
qDebug() << "Failed to compile: " + _gridProgram.log();
|
||||
return;
|
||||
}
|
||||
if (!_gridProgram.link()) {
|
||||
qDebug() << "Failed to link: " + _gridProgram.log();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Render code largely taken from MetavoxelEditor::render()
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
glLineWidth(1.5f);
|
||||
|
||||
// center the grid around the camera position on the plane
|
||||
glm::vec3 rotated = glm::inverse(rotation) * Application::getInstance()->getCamera()->getPosition();
|
||||
float spacing = _minorGridWidth;
|
||||
|
||||
float alpha = getAlpha();
|
||||
xColor color = getColor();
|
||||
glm::vec3 position = getPosition();
|
||||
|
||||
const int MINOR_GRID_DIVISIONS = 200;
|
||||
const int MAJOR_GRID_DIVISIONS = 100;
|
||||
const float MAX_COLOR = 255.0f;
|
||||
|
||||
// center the grid around the camera position on the plane
|
||||
glm::vec3 rotated = glm::inverse(_rotation) * Application::getInstance()->getCamera()->getPosition();
|
||||
|
||||
float spacing = _minorGridWidth;
|
||||
|
||||
float alpha = getAlpha();
|
||||
xColor color = getColor();
|
||||
glm::vec4 gridColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||
|
||||
_gridProgram.bind();
|
||||
auto batch = args->_batch;
|
||||
|
||||
// Minor grid
|
||||
glPushMatrix();
|
||||
{
|
||||
glTranslatef(_minorGridWidth * (floorf(rotated.x / spacing) - MINOR_GRID_DIVISIONS / 2),
|
||||
spacing * (floorf(rotated.y / spacing) - MINOR_GRID_DIVISIONS / 2), position.z);
|
||||
if (batch) {
|
||||
Transform transform;
|
||||
transform.setRotation(_rotation);
|
||||
|
||||
float scale = MINOR_GRID_DIVISIONS * spacing;
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(MINOR_GRID_DIVISIONS, MINOR_GRID_DIVISIONS, gridColor);
|
||||
// Minor grid
|
||||
{
|
||||
batch->_glLineWidth(1.0f);
|
||||
auto position = glm::vec3(_minorGridWidth * (floorf(rotated.x / spacing) - MINOR_GRID_DIVISIONS / 2),
|
||||
spacing * (floorf(rotated.y / spacing) - MINOR_GRID_DIVISIONS / 2),
|
||||
_position.z);
|
||||
float scale = MINOR_GRID_DIVISIONS * spacing;
|
||||
|
||||
transform.setTranslation(position);
|
||||
transform.setScale(scale);
|
||||
|
||||
batch->setModelTransform(transform);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(*batch, MINOR_GRID_DIVISIONS, MINOR_GRID_DIVISIONS, gridColor);
|
||||
}
|
||||
|
||||
// Major grid
|
||||
{
|
||||
batch->_glLineWidth(4.0f);
|
||||
spacing *= _majorGridEvery;
|
||||
auto position = glm::vec3(spacing * (floorf(rotated.x / spacing) - MAJOR_GRID_DIVISIONS / 2),
|
||||
spacing * (floorf(rotated.y / spacing) - MAJOR_GRID_DIVISIONS / 2),
|
||||
_position.z);
|
||||
float scale = MAJOR_GRID_DIVISIONS * spacing;
|
||||
|
||||
transform.setTranslation(position);
|
||||
transform.setScale(scale);
|
||||
|
||||
batch->setModelTransform(transform);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(*batch, MAJOR_GRID_DIVISIONS, MAJOR_GRID_DIVISIONS, gridColor);
|
||||
}
|
||||
} else {
|
||||
if (!_gridProgram.isLinked()) {
|
||||
if (!_gridProgram.addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/grid.vert")) {
|
||||
qDebug() << "Failed to compile: " + _gridProgram.log();
|
||||
return;
|
||||
}
|
||||
if (!_gridProgram.addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/grid.frag")) {
|
||||
qDebug() << "Failed to compile: " + _gridProgram.log();
|
||||
return;
|
||||
}
|
||||
if (!_gridProgram.link()) {
|
||||
qDebug() << "Failed to link: " + _gridProgram.log();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Render code largely taken from MetavoxelEditor::render()
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
glLineWidth(1.5f);
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
|
||||
_gridProgram.bind();
|
||||
|
||||
// Minor grid
|
||||
glPushMatrix();
|
||||
{
|
||||
glTranslatef(_minorGridWidth * (floorf(rotated.x / spacing) - MINOR_GRID_DIVISIONS / 2),
|
||||
spacing * (floorf(rotated.y / spacing) - MINOR_GRID_DIVISIONS / 2), position.z);
|
||||
|
||||
float scale = MINOR_GRID_DIVISIONS * spacing;
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(MINOR_GRID_DIVISIONS, MINOR_GRID_DIVISIONS, gridColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
// Major grid
|
||||
glPushMatrix();
|
||||
{
|
||||
glLineWidth(4.0f);
|
||||
spacing *= _majorGridEvery;
|
||||
glTranslatef(spacing * (floorf(rotated.x / spacing) - MAJOR_GRID_DIVISIONS / 2),
|
||||
spacing * (floorf(rotated.y / spacing) - MAJOR_GRID_DIVISIONS / 2), position.z);
|
||||
|
||||
float scale = MAJOR_GRID_DIVISIONS * spacing;
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(MAJOR_GRID_DIVISIONS, MAJOR_GRID_DIVISIONS, gridColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
_gridProgram.release();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
// Major grid
|
||||
glPushMatrix();
|
||||
{
|
||||
glLineWidth(4.0f);
|
||||
spacing *= _majorGridEvery;
|
||||
glTranslatef(spacing * (floorf(rotated.x / spacing) - MAJOR_GRID_DIVISIONS / 2),
|
||||
spacing * (floorf(rotated.y / spacing) - MAJOR_GRID_DIVISIONS / 2), position.z);
|
||||
|
||||
float scale = MAJOR_GRID_DIVISIONS * spacing;
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(MAJOR_GRID_DIVISIONS, MAJOR_GRID_DIVISIONS, gridColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
_gridProgram.release();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
void Grid3DOverlay::setProperties(const QScriptValue& properties) {
|
||||
|
|
|
@ -37,41 +37,57 @@ void Line3DOverlay::render(RenderArgs* args) {
|
|||
return; // do nothing if we're not visible
|
||||
}
|
||||
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glLineWidth(_lineWidth);
|
||||
|
||||
float alpha = getAlpha();
|
||||
xColor color = getColor();
|
||||
const float MAX_COLOR = 255.0f;
|
||||
glm::vec4 colorv4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
glm::quat rotation = getRotation();
|
||||
auto batch = args->_batch;
|
||||
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
if (batch) {
|
||||
Transform transform;
|
||||
transform.setTranslation(_position);
|
||||
transform.setRotation(_rotation);
|
||||
batch->setModelTransform(transform);
|
||||
|
||||
if (getIsDashedLine()) {
|
||||
// TODO: add support for color to renderDashedLine()
|
||||
DependencyManager::get<GeometryCache>()->renderDashedLine(_position, _end, colorv4, _geometryCacheID);
|
||||
if (getIsDashedLine()) {
|
||||
// TODO: add support for color to renderDashedLine()
|
||||
DependencyManager::get<GeometryCache>()->renderDashedLine(*batch, _position, _end, colorv4, _geometryCacheID);
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->renderLine(*batch, _start, _end, colorv4, _geometryCacheID);
|
||||
}
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->renderLine(_start, _end, colorv4, _geometryCacheID);
|
||||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
glDisable(GL_LIGHTING);
|
||||
glLineWidth(_lineWidth);
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
if (getIsDashedLine()) {
|
||||
// TODO: add support for color to renderDashedLine()
|
||||
DependencyManager::get<GeometryCache>()->renderDashedLine(_position, _end, colorv4, _geometryCacheID);
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->renderLine(_start, _end, colorv4, _geometryCacheID);
|
||||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,8 @@ namespace render {
|
|||
}
|
||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||
if (args) {
|
||||
glPushMatrix();
|
||||
if (overlay->getAnchor() == Overlay::MY_AVATAR) {
|
||||
glPushMatrix();
|
||||
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
glm::quat myAvatarRotation = avatar->getOrientation();
|
||||
glm::vec3 myAvatarPosition = avatar->getPosition();
|
||||
|
@ -78,9 +78,11 @@ namespace render {
|
|||
glTranslatef(myAvatarPosition.x, myAvatarPosition.y, myAvatarPosition.z);
|
||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
||||
glScalef(myAvatarScale, myAvatarScale, myAvatarScale);
|
||||
overlay->render(args);
|
||||
glPopMatrix();
|
||||
} else {
|
||||
overlay->render(args);
|
||||
}
|
||||
overlay->render(args);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,74 +41,116 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
|
|||
const float MAX_COLOR = 255.0f;
|
||||
glm::vec4 rectangleColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 center = getCenter();
|
||||
glm::vec2 dimensions = getDimensions();
|
||||
glm::vec2 halfDimensions = dimensions * 0.5f;
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
auto batch = args->_batch;
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
//glScalef(dimensions.x, dimensions.y, 1.0f);
|
||||
if (batch) {
|
||||
Transform transform;
|
||||
transform.setTranslation(position);
|
||||
transform.setRotation(rotation);
|
||||
|
||||
glLineWidth(_lineWidth);
|
||||
batch->setModelTransform(transform);
|
||||
|
||||
if (getIsSolid()) {
|
||||
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(*batch, topLeft, bottomRight, rectangleColor);
|
||||
} else {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (getIsDashedLine()) {
|
||||
glm::vec3 point1(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 point2(halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 point3(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
glm::vec3 point4(-halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
|
||||
// for our overlay, is solid means we draw a solid "filled" rectangle otherwise we just draw a border line...
|
||||
if (getIsSolid()) {
|
||||
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, rectangleColor);
|
||||
geometryCache->renderDashedLine(*batch, point1, point2, rectangleColor);
|
||||
geometryCache->renderDashedLine(*batch, point2, point3, rectangleColor);
|
||||
geometryCache->renderDashedLine(*batch, point3, point4, rectangleColor);
|
||||
geometryCache->renderDashedLine(*batch, point4, point1, rectangleColor);
|
||||
} else {
|
||||
if (getIsDashedLine()) {
|
||||
if (halfDimensions != _previousHalfDimensions) {
|
||||
QVector<glm::vec3> border;
|
||||
border << glm::vec3(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(-halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
geometryCache->updateVertices(_geometryCacheID, border, rectangleColor);
|
||||
|
||||
glm::vec3 point1(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 point2(halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 point3(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
glm::vec3 point4(-halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
|
||||
geometryCache->renderDashedLine(point1, point2, rectangleColor);
|
||||
geometryCache->renderDashedLine(point2, point3, rectangleColor);
|
||||
geometryCache->renderDashedLine(point3, point4, rectangleColor);
|
||||
geometryCache->renderDashedLine(point4, point1, rectangleColor);
|
||||
|
||||
} else {
|
||||
|
||||
if (halfDimensions != _previousHalfDimensions) {
|
||||
QVector<glm::vec3> border;
|
||||
border << glm::vec3(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(-halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
geometryCache->updateVertices(_geometryCacheID, border, rectangleColor);
|
||||
|
||||
_previousHalfDimensions = halfDimensions;
|
||||
|
||||
}
|
||||
geometryCache->renderVertices(gpu::LINE_STRIP, _geometryCacheID);
|
||||
_previousHalfDimensions = halfDimensions;
|
||||
}
|
||||
geometryCache->renderVertices(*batch, gpu::LINE_STRIP, _geometryCacheID);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
//glScalef(dimensions.x, dimensions.y, 1.0f);
|
||||
|
||||
glLineWidth(_lineWidth);
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
// for our overlay, is solid means we draw a solid "filled" rectangle otherwise we just draw a border line...
|
||||
if (getIsSolid()) {
|
||||
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, rectangleColor);
|
||||
} else {
|
||||
if (getIsDashedLine()) {
|
||||
|
||||
glm::vec3 point1(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 point2(halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 point3(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
glm::vec3 point4(-halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
|
||||
geometryCache->renderDashedLine(point1, point2, rectangleColor);
|
||||
geometryCache->renderDashedLine(point2, point3, rectangleColor);
|
||||
geometryCache->renderDashedLine(point3, point4, rectangleColor);
|
||||
geometryCache->renderDashedLine(point4, point1, rectangleColor);
|
||||
|
||||
} else {
|
||||
|
||||
if (halfDimensions != _previousHalfDimensions) {
|
||||
QVector<glm::vec3> border;
|
||||
border << glm::vec3(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(-halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
geometryCache->updateVertices(_geometryCacheID, border, rectangleColor);
|
||||
|
||||
_previousHalfDimensions = halfDimensions;
|
||||
|
||||
}
|
||||
geometryCache->renderVertices(gpu::LINE_STRIP, _geometryCacheID);
|
||||
}
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,33 +39,45 @@ void Sphere3DOverlay::render(RenderArgs* args) {
|
|||
const float MAX_COLOR = 255.0f;
|
||||
glm::vec4 sphereColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 center = getCenter();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
auto batch = args->_batch;
|
||||
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
if (batch) {
|
||||
Transform transform;
|
||||
transform.setTranslation(_position);
|
||||
transform.setRotation(_rotation);
|
||||
transform.setScale(_dimensions);
|
||||
|
||||
batch->setModelTransform(transform);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(*batch, 1.0f, SLICES, SLICES, sphereColor, _isSolid);
|
||||
} else {
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 center = getCenter();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(1.0f, SLICES, SLICES, sphereColor, _isSolid);
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(1.0f, SLICES, SLICES, sphereColor, _isSolid);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>750</width>
|
||||
<height>213</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Update Required</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<widget class="QLabel" name="updateContent">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>50</x>
|
||||
<y>20</y>
|
||||
<width>641</width>
|
||||
<height>111</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
<pointsize>-1</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font-family: Arial;
|
||||
font-size: 20px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>360</x>
|
||||
<y>160</y>
|
||||
<width>374</width>
|
||||
<height>42</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="downloadButton">
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"> background-color: #333333;
|
||||
border-width: 0;
|
||||
border-radius: 9px;
|
||||
border-radius: 9px;
|
||||
font-family: Arial;
|
||||
font-size: 18px;
|
||||
font-weight: 100;
|
||||
color: #b7b7b7;
|
||||
width: 120px;
|
||||
height: 40px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Download</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="skipButton">
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"> background-color: #333333;
|
||||
border-width: 0;
|
||||
border-radius: 9px;
|
||||
border-radius: 9px;
|
||||
font-family: Arial;
|
||||
font-size: 18px;
|
||||
font-weight: 100;
|
||||
color: #b7b7b7;
|
||||
width: 120px;
|
||||
height: 40px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Skip Version</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="closeButton">
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"> background-color: #333333;
|
||||
border-width: 0;
|
||||
border-radius: 9px;
|
||||
border-radius: 9px;
|
||||
font-family: Arial;
|
||||
font-size: 18px;
|
||||
font-weight: 100;
|
||||
color: #b7b7b7;
|
||||
width: 120px;
|
||||
height: 40px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -156,6 +156,7 @@ void AudioClient::audioMixerKilled() {
|
|||
_hasReceivedFirstPacket = false;
|
||||
_outgoingAvatarAudioSequenceNumber = 0;
|
||||
_stats.reset();
|
||||
emit disconnected();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -186,6 +186,7 @@ signals:
|
|||
void deviceChanged();
|
||||
|
||||
void receivedFirstPacket();
|
||||
void disconnected();
|
||||
|
||||
protected:
|
||||
AudioClient();
|
||||
|
|
3
libraries/auto-updater/CMakeLists.txt
Normal file
3
libraries/auto-updater/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
set(TARGET_NAME auto-updater)
|
||||
setup_hifi_library(Network)
|
||||
link_hifi_libraries(shared networking)
|
144
libraries/auto-updater/src/AutoUpdater.cpp
Normal file
144
libraries/auto-updater/src/AutoUpdater.cpp
Normal file
|
@ -0,0 +1,144 @@
|
|||
//
|
||||
// AutoUpdater.cpp
|
||||
// libraries/auto-update/src
|
||||
//
|
||||
// Created by Leonardo Murillo on 6/1/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
|
||||
//
|
||||
|
||||
#include "AutoUpdater.h"
|
||||
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
AutoUpdater::AutoUpdater() {
|
||||
#if defined Q_OS_WIN32
|
||||
_operatingSystem = "windows";
|
||||
#elif defined Q_OS_MAC
|
||||
_operatingSystem = "mac";
|
||||
#elif defined Q_OS_LINUX
|
||||
_operatingSystem = "ubuntu";
|
||||
#endif
|
||||
|
||||
connect(this, SIGNAL(latestVersionDataParsed()), this, SLOT(checkVersionAndNotify()));
|
||||
}
|
||||
|
||||
void AutoUpdater::checkForUpdate() {
|
||||
this->getLatestVersionData();
|
||||
}
|
||||
|
||||
void AutoUpdater::getLatestVersionData() {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest latestVersionRequest(BUILDS_XML_URL);
|
||||
latestVersionRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(latestVersionRequest);
|
||||
connect(reply, &QNetworkReply::finished, this, &AutoUpdater::parseLatestVersionData);
|
||||
}
|
||||
|
||||
void AutoUpdater::parseLatestVersionData() {
|
||||
QNetworkReply* sender = qobject_cast<QNetworkReply*>(QObject::sender());
|
||||
|
||||
QXmlStreamReader xml(sender);
|
||||
|
||||
int version;
|
||||
QString downloadUrl;
|
||||
QString releaseTime;
|
||||
QString releaseNotes;
|
||||
QString commitSha;
|
||||
QString pullRequestNumber;
|
||||
|
||||
while (!xml.atEnd() && !xml.hasError()) {
|
||||
if (xml.name().toString() == "project" &&
|
||||
xml.attributes().hasAttribute("name") &&
|
||||
xml.attributes().value("name").toString() == "interface") {
|
||||
xml.readNext();
|
||||
|
||||
while (!xml.atEnd() && !xml.hasError() && xml.name().toString() != "project") {
|
||||
if (xml.name().toString() == "platform" &&
|
||||
xml.attributes().hasAttribute("name") &&
|
||||
xml.attributes().value("name").toString() == _operatingSystem) {
|
||||
xml.readNext();
|
||||
while (!xml.atEnd() && !xml.hasError() &&
|
||||
xml.name().toString() != "platform") {
|
||||
|
||||
if (xml.name().toString() == "build" && xml.tokenType() != QXmlStreamReader::EndElement) {
|
||||
xml.readNext();
|
||||
version = xml.readElementText().toInt();
|
||||
xml.readNext();
|
||||
downloadUrl = xml.readElementText();
|
||||
xml.readNext();
|
||||
releaseTime = xml.readElementText();
|
||||
xml.readNext();
|
||||
if (xml.name().toString() == "notes" && xml.tokenType() != QXmlStreamReader::EndElement) {
|
||||
xml.readNext();
|
||||
while (!xml.atEnd() && !xml.hasError() && xml.name().toString() != "notes") {
|
||||
if (xml.name().toString() == "note" && xml.tokenType() != QXmlStreamReader::EndElement) {
|
||||
releaseNotes = releaseNotes + "\n" + xml.readElementText();
|
||||
}
|
||||
xml.readNext();
|
||||
}
|
||||
}
|
||||
xml.readNext();
|
||||
commitSha = xml.readElementText();
|
||||
xml.readNext();
|
||||
pullRequestNumber = xml.readElementText();
|
||||
appendBuildData(version, downloadUrl, releaseTime, releaseNotes, pullRequestNumber);
|
||||
releaseNotes = "";
|
||||
}
|
||||
|
||||
xml.readNext();
|
||||
}
|
||||
}
|
||||
xml.readNext();
|
||||
}
|
||||
|
||||
} else {
|
||||
xml.readNext();
|
||||
}
|
||||
}
|
||||
sender->deleteLater();
|
||||
emit latestVersionDataParsed();
|
||||
}
|
||||
|
||||
void AutoUpdater::checkVersionAndNotify() {
|
||||
if (QCoreApplication::applicationVersion() == "dev" || _builds.empty()) {
|
||||
// No version checking is required in dev builds or when no build
|
||||
// data was found for the platform
|
||||
return;
|
||||
}
|
||||
int latestVersionAvailable = _builds.lastKey();
|
||||
if (QCoreApplication::applicationVersion().toInt() < latestVersionAvailable) {
|
||||
emit newVersionIsAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
void AutoUpdater::performAutoUpdate(int version) {
|
||||
// NOTE: This is not yet auto updating - however this is a checkpoint towards that end
|
||||
// Next PR will handle the automatic download, upgrading and application restart
|
||||
const QMap<QString, QString>& chosenVersion = _builds.value(version);
|
||||
const QUrl& downloadUrl = chosenVersion.value("downloadUrl");
|
||||
QDesktopServices::openUrl(downloadUrl);
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
void AutoUpdater::downloadUpdateVersion(int version) {
|
||||
emit newVersionIsDownloaded();
|
||||
}
|
||||
|
||||
void AutoUpdater::appendBuildData(int versionNumber,
|
||||
const QString& downloadURL,
|
||||
const QString& releaseTime,
|
||||
const QString& releaseNotes,
|
||||
const QString& pullRequestNumber) {
|
||||
|
||||
QMap<QString, QString> thisBuildDetails;
|
||||
thisBuildDetails.insert("downloadUrl", downloadURL);
|
||||
thisBuildDetails.insert("releaseTime", releaseTime);
|
||||
thisBuildDetails.insert("releaseNotes", releaseNotes);
|
||||
thisBuildDetails.insert("pullRequestNumber", pullRequestNumber);
|
||||
_builds.insert(versionNumber, thisBuildDetails);
|
||||
|
||||
}
|
68
libraries/auto-updater/src/AutoUpdater.h
Normal file
68
libraries/auto-updater/src/AutoUpdater.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// AutoUpdater.h
|
||||
// libraries/auto-update/src
|
||||
//
|
||||
// Created by Leonardo Murillo on 6/1/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
|
||||
//
|
||||
|
||||
#ifndef hifi_AutoUpdater_h
|
||||
#define hifi_AutoUpdater_h
|
||||
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QXmlStreamAttributes>
|
||||
#include <QtCore/QXmlStreamReader>
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkConfiguration>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
const QUrl BUILDS_XML_URL("https://highfidelity.com/builds.xml");
|
||||
|
||||
class AutoUpdater : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
AutoUpdater();
|
||||
|
||||
void checkForUpdate();
|
||||
const QMap<int, QMap<QString, QString>>& getBuildData() { return _builds; }
|
||||
void performAutoUpdate(int version);
|
||||
|
||||
signals:
|
||||
void latestVersionDataParsed();
|
||||
void newVersionIsAvailable();
|
||||
void newVersionIsDownloaded();
|
||||
|
||||
private:
|
||||
QMap<int, QMap<QString, QString>> _builds;
|
||||
QString _operatingSystem;
|
||||
|
||||
void getLatestVersionData();
|
||||
void downloadUpdateVersion(int version);
|
||||
void appendBuildData(int versionNumber,
|
||||
const QString& downloadURL,
|
||||
const QString& releaseTime,
|
||||
const QString& releaseNotes,
|
||||
const QString& pullRequestNumber);
|
||||
|
||||
private slots:
|
||||
void parseLatestVersionData();
|
||||
void checkVersionAndNotify();
|
||||
};
|
||||
|
||||
#endif // _hifi_AutoUpdater_h
|
|
@ -49,6 +49,7 @@ void RenderableLineEntityItem::render(RenderArgs* args) {
|
|||
|
||||
batch._glLineWidth(getLineWidth());
|
||||
if (getLinePoints().size() > 1) {
|
||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
|
||||
DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID);
|
||||
}
|
||||
batch._glLineWidth(1.0f);
|
||||
|
|
|
@ -41,7 +41,11 @@ public:
|
|||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||
|
||||
virtual void somethingChangedNotification() { _needsInitialSimulation = true; }
|
||||
virtual void somethingChangedNotification() {
|
||||
// FIX ME: this is overly aggressive. We only really need to simulate() if something about
|
||||
// the world space transform has changed and/or if some animation is occurring.
|
||||
_needsInitialSimulation = true;
|
||||
}
|
||||
|
||||
virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr);
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
|
|
|
@ -53,6 +53,7 @@ void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
|
|||
batch.setUniformTexture(0, _texture->getGPUTexture());
|
||||
}
|
||||
batch.setModelTransform(getTransformToCenter());
|
||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, textured);
|
||||
DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::QUADS, _cacheID);
|
||||
};
|
||||
|
||||
|
@ -74,31 +75,34 @@ void RenderableParticleEffectEntityItem::updateQuads(RenderArgs* args, bool text
|
|||
vertices.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE);
|
||||
|
||||
if (textured) {
|
||||
positions.reserve(getLivingParticleCount());
|
||||
textureCoords.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE);
|
||||
|
||||
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
|
||||
positions.append(_particlePositions[i]);
|
||||
|
||||
}
|
||||
positions.reserve(getLivingParticleCount());
|
||||
|
||||
|
||||
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
|
||||
positions.append(_particlePositions[i]);
|
||||
if (textured) {
|
||||
textureCoords.append(glm::vec2(0, 1));
|
||||
textureCoords.append(glm::vec2(1, 1));
|
||||
textureCoords.append(glm::vec2(1, 0));
|
||||
textureCoords.append(glm::vec2(0, 0));
|
||||
}
|
||||
|
||||
// sort particles back to front
|
||||
::zSortAxis = args->_viewFrustum->getDirection();
|
||||
qSort(positions.begin(), positions.end(), zSort);
|
||||
}
|
||||
|
||||
// sort particles back to front
|
||||
::zSortAxis = args->_viewFrustum->getDirection();
|
||||
qSort(positions.begin(), positions.end(), zSort);
|
||||
|
||||
for (int i = 0; i < positions.size(); i++) {
|
||||
glm::vec3 pos = (textured) ? positions[i] : _particlePositions[i];
|
||||
|
||||
// generate corners of quad aligned to face the camera.
|
||||
vertices.append(pos - rightOffset + upOffset);
|
||||
vertices.append(pos + rightOffset + upOffset);
|
||||
vertices.append(pos + rightOffset - upOffset);
|
||||
vertices.append(pos - rightOffset + upOffset);
|
||||
vertices.append(pos - rightOffset - upOffset);
|
||||
vertices.append(pos + rightOffset - upOffset);
|
||||
|
||||
}
|
||||
|
||||
if (textured) {
|
||||
|
|
|
@ -121,7 +121,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize)
|
|||
_volData->setBorderValue(255);
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug() << " new size is" << _volData->getWidth() << _volData->getHeight() << _volData->getDepth();
|
||||
qDebug() << " new voxel-space size is" << _volData->getWidth() << _volData->getHeight() << _volData->getDepth();
|
||||
#endif
|
||||
|
||||
// I'm not sure this is needed... the docs say that each element is initialized with its default
|
||||
|
@ -220,12 +220,15 @@ uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) {
|
|||
return _volData->getVoxelAt(x, y, z);
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) {
|
||||
void RenderablePolyVoxEntityItem::setVoxelInternal(int x, int y, int z, uint8_t toValue) {
|
||||
// set a voxel without recompressing the voxel data
|
||||
assert(_volData);
|
||||
if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateOnCount(x, y, z, toValue);
|
||||
|
||||
if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
|
||||
_volData->setVoxelAt(x + 1, y + 1, z + 1, toValue);
|
||||
} else {
|
||||
|
@ -234,6 +237,14 @@ void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue)
|
|||
}
|
||||
|
||||
|
||||
void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) {
|
||||
if (_locked) {
|
||||
return;
|
||||
}
|
||||
setVoxelInternal(x, y, z, toValue);
|
||||
compressVolumeData();
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toValue) {
|
||||
// keep _onCount up to date
|
||||
if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) {
|
||||
|
@ -255,11 +266,15 @@ void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toV
|
|||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) {
|
||||
if (_locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int z = 0; z < _voxelVolumeSize.z; z++) {
|
||||
for (int y = 0; y < _voxelVolumeSize.y; y++) {
|
||||
for (int x = 0; x < _voxelVolumeSize.x; x++) {
|
||||
updateOnCount(x, y, z, toValue);
|
||||
setVoxel(x, y, z, toValue);
|
||||
setVoxelInternal(x, y, z, toValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -267,11 +282,19 @@ void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) {
|
|||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setVoxelInVolume(glm::vec3 position, uint8_t toValue) {
|
||||
updateOnCount(position.x, position.y, position.z, toValue);
|
||||
setVoxel(position.x, position.y, position.z, toValue);
|
||||
if (_locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
// same as setVoxel but takes a vector rather than 3 floats.
|
||||
setVoxel((int)position.x, (int)position.y, (int)position.z, toValue);
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) {
|
||||
if (_locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This three-level for loop iterates over every voxel in the volume
|
||||
for (int z = 0; z < _voxelVolumeSize.z; z++) {
|
||||
for (int y = 0; y < _voxelVolumeSize.y; y++) {
|
||||
|
@ -283,7 +306,7 @@ void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi
|
|||
// If the current voxel is less than 'radius' units from the center then we make it solid.
|
||||
if (fDistToCenter <= radius) {
|
||||
updateOnCount(x, y, z, toValue);
|
||||
setVoxel(x, y, z, toValue);
|
||||
setVoxelInternal(x, y, z, toValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -380,10 +403,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
|||
getModel();
|
||||
}
|
||||
|
||||
Transform transform;
|
||||
transform.setTranslation(getPosition() - getRegistrationPoint() * getDimensions());
|
||||
transform.setRotation(getRotation());
|
||||
transform.setScale(getDimensions() / _voxelVolumeSize);
|
||||
Transform transform(voxelToWorldMatrix());
|
||||
|
||||
auto mesh = _modelGeometry.getMesh();
|
||||
Q_ASSERT(args->_batch);
|
||||
|
@ -514,6 +534,11 @@ void RenderablePolyVoxEntityItem::compressVolumeData() {
|
|||
|
||||
QByteArray newVoxelData;
|
||||
QDataStream writer(&newVoxelData, QIODevice::WriteOnly | QIODevice::Truncate);
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug() << "compressing voxel data of size:" << voxelXSize << voxelYSize << voxelZSize;
|
||||
#endif
|
||||
|
||||
writer << voxelXSize << voxelYSize << voxelZSize;
|
||||
|
||||
QByteArray compressedData = qCompress(uncompressedData, 9);
|
||||
|
@ -573,7 +598,7 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() {
|
|||
for (int x = 0; x < voxelXSize; x++) {
|
||||
int uncompressedIndex = (z * voxelYSize * voxelXSize) + (y * voxelZSize) + x;
|
||||
updateOnCount(x, y, z, uncompressedData[uncompressedIndex]);
|
||||
setVoxel(x, y, z, uncompressedData[uncompressedIndex]);
|
||||
setVoxelInternal(x, y, z, uncompressedData[uncompressedIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,11 +73,12 @@ public:
|
|||
virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
|
||||
private:
|
||||
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
|
||||
// may not match _voxelVolumeSize.
|
||||
|
||||
void setVoxelInternal(int x, int y, int z, uint8_t toValue);
|
||||
void compressVolumeData();
|
||||
void decompressVolumeData();
|
||||
|
||||
|
|
|
@ -47,12 +47,13 @@ void RenderableTextEntityItem::render(RenderArgs* args) {
|
|||
glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, SLIGHTLY_BEHIND);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderQuad(batch, minCorner, maxCorner, backgroundColor);
|
||||
|
||||
float scale = _lineHeight / _textRenderer->getRowHeight();
|
||||
float scale = _lineHeight / _textRenderer->getFontSize();
|
||||
transformToTopLeft.setScale(scale); // Scale to have the correct line height
|
||||
batch.setModelTransform(transformToTopLeft);
|
||||
|
||||
float leftMargin = 0.5f * _lineHeight, topMargin = 0.5f * _lineHeight;
|
||||
glm::vec2 bounds = glm::vec2(dimensions.x - 2.0f * leftMargin, dimensions.y - 2.0f * topMargin);
|
||||
float leftMargin = 0.1f * _lineHeight, topMargin = 0.1f * _lineHeight;
|
||||
glm::vec2 bounds = glm::vec2(dimensions.x - 2.0f * leftMargin,
|
||||
dimensions.y - 2.0f * topMargin);
|
||||
_textRenderer->draw(batch, leftMargin / scale, -topMargin / scale, _text, textColor, bounds / scale);
|
||||
}
|
||||
|
||||
|
|
|
@ -67,12 +67,12 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
|||
_simulatorIDChangedTime(0),
|
||||
_marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID),
|
||||
_name(ENTITY_ITEM_DEFAULT_NAME),
|
||||
_href(""),
|
||||
_description(""),
|
||||
_dirtyFlags(0),
|
||||
_element(nullptr),
|
||||
_physicsInfo(nullptr),
|
||||
_simulated(false),
|
||||
_href(""),
|
||||
_description("")
|
||||
_simulated(false)
|
||||
{
|
||||
quint64 now = usecTimestampNow();
|
||||
_lastSimulated = now;
|
||||
|
|
|
@ -392,17 +392,20 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
|
|||
|
||||
// If we wrote fewer entities than we expected, update the number of entities in our packet
|
||||
bool successUpdateEntityCount = true;
|
||||
if (!noEntitiesFit && numberOfEntities != actualNumberOfEntities) {
|
||||
if (numberOfEntities != actualNumberOfEntities) {
|
||||
successUpdateEntityCount = packetData->updatePriorBytes(numberOfEntitiesOffset,
|
||||
(const unsigned char*)&actualNumberOfEntities, sizeof(actualNumberOfEntities));
|
||||
}
|
||||
|
||||
// If we weren't able to update our entity count, or we couldn't fit any entities, then
|
||||
// we should discard our element and return a result of NONE
|
||||
if (!successUpdateEntityCount || noEntitiesFit) {
|
||||
if (!successUpdateEntityCount) {
|
||||
packetData->discardLevel(elementLevel);
|
||||
appendElementState = OctreeElement::NONE;
|
||||
} else {
|
||||
if (noEntitiesFit) {
|
||||
appendElementState = OctreeElement::PARTIAL;
|
||||
}
|
||||
packetData->endLevel(elementLevel);
|
||||
}
|
||||
return appendElementState;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
const glm::vec3 PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE = glm::vec3(32, 32, 32);
|
||||
const float PolyVoxEntityItem::MAX_VOXEL_DIMENSION = 32.0f;
|
||||
const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(qCompress(QByteArray(0), 9)); // XXX
|
||||
const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(PolyVoxEntityItem::makeEmptyVoxelData());
|
||||
const PolyVoxEntityItem::PolyVoxSurfaceStyle PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE =
|
||||
PolyVoxEntityItem::SURFACE_MARCHING_CUBES;
|
||||
|
||||
|
@ -31,6 +31,25 @@ EntityItemPointer PolyVoxEntityItem::factory(const EntityItemID& entityID, const
|
|||
return EntityItemPointer(new PolyVoxEntityItem(entityID, properties));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QByteArray PolyVoxEntityItem::makeEmptyVoxelData(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) {
|
||||
int rawSize = voxelXSize * voxelYSize * voxelZSize;
|
||||
|
||||
QByteArray uncompressedData = QByteArray(rawSize, '\0');
|
||||
QByteArray newVoxelData;
|
||||
QDataStream writer(&newVoxelData, QIODevice::WriteOnly | QIODevice::Truncate);
|
||||
writer << voxelXSize << voxelYSize << voxelZSize;
|
||||
|
||||
QByteArray compressedData = qCompress(uncompressedData, 9);
|
||||
writer << compressedData;
|
||||
|
||||
return newVoxelData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||
EntityItem(entityItemID),
|
||||
_voxelVolumeSize(PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE),
|
||||
|
|
|
@ -12,14 +12,14 @@
|
|||
#ifndef hifi_PolyVoxEntityItem_h
|
||||
#define hifi_PolyVoxEntityItem_h
|
||||
|
||||
#include "EntityItem.h"
|
||||
#include "EntityItem.h"
|
||||
|
||||
class PolyVoxEntityItem : public EntityItem {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
PolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
|
||||
|
||||
|
||||
ALLOW_INSTANTIATION // This class can be instantiated
|
||||
|
||||
// methods for getting/setting all properties of an entity
|
||||
|
@ -29,22 +29,22 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
|
||||
|
||||
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
|
||||
EntityPropertyFlags& requestedProperties,
|
||||
EntityPropertyFlags& propertyFlags,
|
||||
EntityPropertyFlags& propertiesDidntFit,
|
||||
int& propertyCount,
|
||||
int& propertyCount,
|
||||
OctreeElement::AppendState& appendState) const;
|
||||
|
||||
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||
|
||||
|
||||
// never have a ray intersection pick a PolyVoxEntityItem.
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const { return false; }
|
||||
|
||||
virtual void debugDump() const;
|
||||
|
@ -58,12 +58,12 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
enum PolyVoxSurfaceStyle {
|
||||
SURFACE_MARCHING_CUBES,
|
||||
SURFACE_CUBIC,
|
||||
SURFACE_EDGED_CUBIC
|
||||
SURFACE_EDGED_CUBIC
|
||||
};
|
||||
|
||||
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; }
|
||||
virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) {
|
||||
setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle);
|
||||
setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle);
|
||||
}
|
||||
virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; }
|
||||
|
||||
|
@ -82,10 +82,11 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
virtual void setAll(uint8_t toValue) {}
|
||||
|
||||
virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue) {}
|
||||
|
||||
|
||||
virtual uint8_t getVoxel(int x, int y, int z) { return 0; }
|
||||
virtual void setVoxel(int x, int y, int z, uint8_t toValue) {}
|
||||
|
||||
static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16);
|
||||
|
||||
protected:
|
||||
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
|
||||
|
|
|
@ -150,6 +150,8 @@ public:
|
|||
void _glUseProgram(GLuint program);
|
||||
void _glUniform1f(GLint location, GLfloat v0);
|
||||
void _glUniform2f(GLint location, GLfloat v0, GLfloat v1);
|
||||
void _glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||
void _glUniform3fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void _glUniform4fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void _glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
|
||||
|
@ -210,6 +212,8 @@ public:
|
|||
COMMAND_glUseProgram,
|
||||
COMMAND_glUniform1f,
|
||||
COMMAND_glUniform2f,
|
||||
COMMAND_glUniform3f,
|
||||
COMMAND_glUniform3fv,
|
||||
COMMAND_glUniform4fv,
|
||||
COMMAND_glUniformMatrix4fv,
|
||||
|
||||
|
|
|
@ -61,6 +61,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::GLBackend::do_glUseProgram),
|
||||
(&::gpu::GLBackend::do_glUniform1f),
|
||||
(&::gpu::GLBackend::do_glUniform2f),
|
||||
(&::gpu::GLBackend::do_glUniform3f),
|
||||
(&::gpu::GLBackend::do_glUniform3fv),
|
||||
(&::gpu::GLBackend::do_glUniform4fv),
|
||||
(&::gpu::GLBackend::do_glUniformMatrix4fv),
|
||||
|
||||
|
@ -462,6 +464,7 @@ void Batch::_glUniform2f(GLint location, GLfloat v0, GLfloat v1) {
|
|||
|
||||
DO_IT_NOW(_glUniform2f, 1);
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
|
@ -475,6 +478,56 @@ void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) {
|
|||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void Batch::_glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {
|
||||
ADD_COMMAND_GL(glUniform3f);
|
||||
|
||||
_params.push_back(v2);
|
||||
_params.push_back(v1);
|
||||
_params.push_back(v0);
|
||||
_params.push_back(location);
|
||||
|
||||
DO_IT_NOW(_glUniform3f, 1);
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform3f(Batch& batch, uint32 paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
glUniform3f(
|
||||
batch._params[paramOffset + 3]._int,
|
||||
batch._params[paramOffset + 2]._float,
|
||||
batch._params[paramOffset + 1]._float,
|
||||
batch._params[paramOffset + 0]._float);
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void Batch::_glUniform3fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
ADD_COMMAND_GL(glUniform3fv);
|
||||
|
||||
const int VEC3_SIZE = 3 * sizeof(float);
|
||||
_params.push_back(cacheData(count * VEC3_SIZE, value));
|
||||
_params.push_back(count);
|
||||
_params.push_back(location);
|
||||
|
||||
DO_IT_NOW(_glUniform3fv, 3);
|
||||
}
|
||||
void GLBackend::do_glUniform3fv(Batch& batch, uint32 paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
glUniform3fv(
|
||||
batch._params[paramOffset + 2]._int,
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint));
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
||||
void Batch::_glUniform4fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
ADD_COMMAND_GL(glUniform4fv);
|
||||
|
||||
|
|
|
@ -379,6 +379,8 @@ protected:
|
|||
void do_glUseProgram(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform1f(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform2f(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform3f(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform3fv(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform4fv(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset);
|
||||
|
||||
|
|
|
@ -61,7 +61,11 @@ void makeBindings(GLBackend::GLShader* shader) {
|
|||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "texcoord");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "attribTexcoord");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "attribTexcoord");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "tangent");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "tangent");
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
#include <math.h>
|
||||
#include <qcompilerdetection.h>
|
||||
|
||||
#include "SkyFromAtmosphere_vert.h"
|
||||
#include "SkyFromAtmosphere_frag.h"
|
||||
|
||||
using namespace model;
|
||||
|
||||
|
||||
|
@ -207,17 +204,6 @@ SunSkyStage::SunSkyStage() :
|
|||
// Begining of march
|
||||
setYearTime(60.0f);
|
||||
|
||||
auto skyFromAtmosphereVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(SkyFromAtmosphere_vert)));
|
||||
auto skyFromAtmosphereFragment = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(SkyFromAtmosphere_frag)));
|
||||
auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyFromAtmosphereVertex, skyFromAtmosphereFragment));
|
||||
|
||||
auto skyState = gpu::StatePointer(new gpu::State());
|
||||
// skyState->setStencilEnable(false);
|
||||
// skyState->setBlendEnable(false);
|
||||
|
||||
_skyPipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState));
|
||||
|
||||
|
||||
_skybox.reset(new Skybox());
|
||||
_skybox->setColor(Color(1.0f, 0.0f, 0.0f));
|
||||
|
||||
|
@ -306,12 +292,6 @@ void SunSkyStage::updateGraphicsObject() const {
|
|||
case NUM_BACKGROUND_MODES:
|
||||
Q_UNREACHABLE();
|
||||
};
|
||||
|
||||
static int firstTime = 0;
|
||||
if (firstTime == 0) {
|
||||
firstTime++;
|
||||
gpu::Shader::makeProgram(*(_skyPipeline->getProgram()));
|
||||
}
|
||||
}
|
||||
|
||||
void SunSkyStage::setBackgroundMode(BackgroundMode mode) {
|
||||
|
|
|
@ -229,8 +229,6 @@ protected:
|
|||
AtmospherePointer _atmosphere;
|
||||
mutable SkyboxPointer _skybox;
|
||||
|
||||
gpu::PipelinePointer _skyPipeline;
|
||||
|
||||
float _dayTime = 12.0f;
|
||||
int _yearTime = 0;
|
||||
mutable EarthSunModel _earthSunModel;
|
||||
|
|
|
@ -54,9 +54,33 @@ const QUrl AddressManager::currentAddress() const {
|
|||
|
||||
void AddressManager::loadSettings(const QString& lookupString) {
|
||||
if (lookupString.isEmpty()) {
|
||||
handleLookupString(currentAddressHandle.get().toString());
|
||||
handleUrl(currentAddressHandle.get().toString(), LookupTrigger::StartupFromSettings);
|
||||
} else {
|
||||
handleLookupString(lookupString);
|
||||
handleUrl(lookupString, LookupTrigger::StartupFromSettings);
|
||||
}
|
||||
}
|
||||
|
||||
void AddressManager::goBack() {
|
||||
if (_backStack.size() > 0) {
|
||||
// go to that address
|
||||
handleUrl(_backStack.pop(), LookupTrigger::Back);
|
||||
|
||||
if (_backStack.size() == 0) {
|
||||
// the back stack is now empty so it is no longer possible to go back - emit that signal
|
||||
emit goBackPossible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddressManager::goForward() {
|
||||
if (_forwardStack.size() > 0) {
|
||||
// pop a URL from the forwardStack and go to that address
|
||||
handleUrl(_forwardStack.pop(), LookupTrigger::Forward);
|
||||
|
||||
if (_forwardStack.size() == 0) {
|
||||
// the forward stack is empty so it is no longer possible to go forwards - emit that signal
|
||||
emit goForwardPossible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +126,7 @@ const JSONCallbackParameters& AddressManager::apiCallbackParameters() {
|
|||
return callbackParams;
|
||||
}
|
||||
|
||||
bool AddressManager::handleUrl(const QUrl& lookupUrl) {
|
||||
bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
||||
if (lookupUrl.scheme() == HIFI_URL_SCHEME) {
|
||||
|
||||
qCDebug(networking) << "Trying to go to URL" << lookupUrl.toString();
|
||||
|
@ -121,17 +145,17 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl) {
|
|||
// we're assuming this is either a network address or global place name
|
||||
// check if it is a network address first
|
||||
if (handleNetworkAddress(lookupUrl.host()
|
||||
+ (lookupUrl.port() == -1 ? "" : ":" + QString::number(lookupUrl.port())))) {
|
||||
+ (lookupUrl.port() == -1 ? "" : ":" + QString::number(lookupUrl.port())), trigger)) {
|
||||
// we may have a path that defines a relative viewpoint - if so we should jump to that now
|
||||
handlePath(lookupUrl.path());
|
||||
handlePath(lookupUrl.path(), trigger);
|
||||
} else if (handleDomainID(lookupUrl.host())){
|
||||
// no place name - this is probably a domain ID
|
||||
// try to look up the domain ID on the metaverse API
|
||||
attemptDomainIDLookup(lookupUrl.host(), lookupUrl.path());
|
||||
attemptDomainIDLookup(lookupUrl.host(), lookupUrl.path(), trigger);
|
||||
} else {
|
||||
// wasn't an address - lookup the place name
|
||||
// we may have a path that defines a relative viewpoint - pass that through the lookup so we can go to it after
|
||||
attemptPlaceNameLookup(lookupUrl.host(), lookupUrl.path());
|
||||
attemptPlaceNameLookup(lookupUrl.host(), lookupUrl.path(), trigger);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,8 +164,10 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl) {
|
|||
qCDebug(networking) << "Going to relative path" << lookupUrl.path();
|
||||
|
||||
// if this is a relative path then handle it as a relative viewpoint
|
||||
handlePath(lookupUrl.path());
|
||||
handlePath(lookupUrl.path(), trigger, true);
|
||||
emit lookupResultsFinished();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -183,6 +209,7 @@ void AddressManager::handleAPIResponse(QNetworkReply& requestReply) {
|
|||
}
|
||||
|
||||
const char OVERRIDE_PATH_KEY[] = "override_path";
|
||||
const char LOOKUP_TRIGGER_KEY[] = "lookup_trigger";
|
||||
|
||||
void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const QNetworkReply& reply) {
|
||||
|
||||
|
@ -218,7 +245,7 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
|
|||
const QString DOMAIN_NETWORK_PORT_KEY = "network_port";
|
||||
const QString DOMAIN_ICE_SERVER_ADDRESS_KEY = "ice_server_address";
|
||||
|
||||
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::HandleAddress);
|
||||
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::HandleAddress);
|
||||
|
||||
const QString DOMAIN_ID_KEY = "id";
|
||||
QString domainIDString = domainObject[DOMAIN_ID_KEY].toString();
|
||||
|
@ -243,6 +270,8 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
|
|||
emit possibleDomainChangeRequiredViaICEForID(iceServerAddress, domainID);
|
||||
}
|
||||
|
||||
LookupTrigger trigger = (LookupTrigger) reply.property(LOOKUP_TRIGGER_KEY).toInt();
|
||||
|
||||
// set our current root place id to the ID that came back
|
||||
const QString PLACE_ID_KEY = "id";
|
||||
_rootPlaceID = rootMap[PLACE_ID_KEY].toUuid();
|
||||
|
@ -251,16 +280,16 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
|
|||
const QString PLACE_NAME_KEY = "name";
|
||||
QString placeName = rootMap[PLACE_NAME_KEY].toString();
|
||||
if (!placeName.isEmpty()) {
|
||||
setHost(placeName);
|
||||
setHost(placeName, trigger);
|
||||
} else {
|
||||
setHost(domainIDString);
|
||||
setHost(domainIDString, trigger);
|
||||
}
|
||||
|
||||
// check if we had a path to override the path returned
|
||||
QString overridePath = reply.property(OVERRIDE_PATH_KEY).toString();
|
||||
|
||||
if (!overridePath.isEmpty()) {
|
||||
handlePath(overridePath);
|
||||
handlePath(overridePath, trigger);
|
||||
} else {
|
||||
// take the path that came back
|
||||
const QString PLACE_PATH_KEY = "path";
|
||||
|
@ -269,10 +298,14 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
|
|||
bool shouldFaceViewpoint = locationMap.contains(LOCATION_API_ONLINE_KEY);
|
||||
|
||||
if (!returnedPath.isEmpty()) {
|
||||
// try to parse this returned path as a viewpoint, that's the only thing it could be for now
|
||||
if (!handleViewpoint(returnedPath, shouldFaceViewpoint)) {
|
||||
qCDebug(networking) << "Received a location path that was could not be handled as a viewpoint -"
|
||||
<< returnedPath;
|
||||
if (shouldFaceViewpoint) {
|
||||
// try to parse this returned path as a viewpoint, that's the only thing it could be for now
|
||||
if (!handleViewpoint(returnedPath, shouldFaceViewpoint)) {
|
||||
qCDebug(networking) << "Received a location path that was could not be handled as a viewpoint -"
|
||||
<< returnedPath;
|
||||
}
|
||||
} else {
|
||||
handlePath(returnedPath, trigger);
|
||||
}
|
||||
} else {
|
||||
// we didn't override the path or get one back - ask the DS for the viewpoint of its index path
|
||||
|
@ -306,15 +339,20 @@ void AddressManager::handleAPIError(QNetworkReply& errorReply) {
|
|||
|
||||
const QString GET_PLACE = "/api/v1/places/%1";
|
||||
|
||||
void AddressManager::attemptPlaceNameLookup(const QString& lookupString, const QString& overridePath) {
|
||||
void AddressManager::attemptPlaceNameLookup(const QString& lookupString, const QString& overridePath, LookupTrigger trigger) {
|
||||
// assume this is a place name and see if we can get any info on it
|
||||
QString placeName = QUrl::toPercentEncoding(lookupString);
|
||||
|
||||
QVariantMap requestParams;
|
||||
|
||||
// if the user asked for a specific path with this lookup then keep it with the request so we can use it later
|
||||
if (!overridePath.isEmpty()) {
|
||||
requestParams.insert(OVERRIDE_PATH_KEY, overridePath);
|
||||
}
|
||||
|
||||
// remember how this lookup was triggered for history storage handling later
|
||||
requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast<int>(trigger));
|
||||
|
||||
AccountManager::getInstance().sendRequest(GET_PLACE.arg(placeName),
|
||||
AccountManagerAuth::None,
|
||||
QNetworkAccessManager::GetOperation,
|
||||
|
@ -324,15 +362,20 @@ void AddressManager::attemptPlaceNameLookup(const QString& lookupString, const Q
|
|||
|
||||
const QString GET_DOMAIN_ID = "/api/v1/domains/%1";
|
||||
|
||||
void AddressManager::attemptDomainIDLookup(const QString& lookupString, const QString& overridePath) {
|
||||
void AddressManager::attemptDomainIDLookup(const QString& lookupString, const QString& overridePath, LookupTrigger trigger) {
|
||||
// assume this is a domain ID and see if we can get any info on it
|
||||
QString domainID = QUrl::toPercentEncoding(lookupString);
|
||||
|
||||
QVariantMap requestParams;
|
||||
|
||||
// if the user asked for a specific path with this lookup then keep it with the request so we can use it later
|
||||
if (!overridePath.isEmpty()) {
|
||||
requestParams.insert(OVERRIDE_PATH_KEY, overridePath);
|
||||
}
|
||||
|
||||
// remember how this lookup was triggered for history storage handling later
|
||||
requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast<int>(trigger));
|
||||
|
||||
AccountManager::getInstance().sendRequest(GET_DOMAIN_ID.arg(domainID),
|
||||
AccountManagerAuth::None,
|
||||
QNetworkAccessManager::GetOperation,
|
||||
|
@ -340,7 +383,7 @@ void AddressManager::attemptDomainIDLookup(const QString& lookupString, const QS
|
|||
QByteArray(), NULL, requestParams);
|
||||
}
|
||||
|
||||
bool AddressManager::handleNetworkAddress(const QString& lookupString) {
|
||||
bool AddressManager::handleNetworkAddress(const QString& lookupString, LookupTrigger trigger) {
|
||||
const QString IP_ADDRESS_REGEX_STRING = "^((?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}"
|
||||
"(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))(?::(\\d{1,5}))?$";
|
||||
|
||||
|
@ -358,7 +401,7 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString) {
|
|||
}
|
||||
|
||||
emit lookupResultsFinished();
|
||||
setDomainInfo(domainIPString, domainPort);
|
||||
setDomainInfo(domainIPString, domainPort, trigger);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -375,7 +418,7 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString) {
|
|||
}
|
||||
|
||||
emit lookupResultsFinished();
|
||||
setDomainInfo(domainHostname, domainPort);
|
||||
setDomainInfo(domainHostname, domainPort, trigger);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -391,15 +434,26 @@ bool AddressManager::handleDomainID(const QString& host) {
|
|||
return (domainIDRegex.indexIn(host) != -1);
|
||||
}
|
||||
|
||||
void AddressManager::handlePath(const QString& path) {
|
||||
if (!handleViewpoint(path)) {
|
||||
void AddressManager::handlePath(const QString& path, LookupTrigger trigger, bool wasPathOnly) {
|
||||
if (!handleViewpoint(path, false, wasPathOnly)) {
|
||||
qCDebug(networking) << "User entered path could not be handled as a viewpoint - " << path <<
|
||||
"- wll attempt to ask domain-server to resolve.";
|
||||
|
||||
if (!wasPathOnly) {
|
||||
// if we received a path with a host then we need to remember what it was here so we can not
|
||||
// double set add to the history stack once handle viewpoint is called with the result
|
||||
_newHostLookupPath = path;
|
||||
} else {
|
||||
// clear the _newHostLookupPath so it doesn't match when this return comes in
|
||||
_newHostLookupPath = QString();
|
||||
}
|
||||
|
||||
emit pathChangeRequired(path);
|
||||
}
|
||||
}
|
||||
|
||||
bool AddressManager::handleViewpoint(const QString& viewpointString, bool shouldFace) {
|
||||
bool AddressManager::handleViewpoint(const QString& viewpointString, bool shouldFace,
|
||||
bool definitelyPathOnly, const QString& pathString) {
|
||||
const QString FLOAT_REGEX_STRING = "([-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?)";
|
||||
const QString SPACED_COMMA_REGEX_STRING = "\\s*,\\s*";
|
||||
const QString POSITION_REGEX_STRING = QString("\\/") + FLOAT_REGEX_STRING + SPACED_COMMA_REGEX_STRING +
|
||||
|
@ -416,8 +470,18 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should
|
|||
positionRegex.cap(2).toFloat(),
|
||||
positionRegex.cap(3).toFloat());
|
||||
|
||||
// we're about to jump positions - store the current address in our history
|
||||
addCurrentAddressToHistory();
|
||||
// We need to use definitelyPathOnly, pathString and _newHostLookupPath to determine if the current address
|
||||
// should be stored in the history before we ask for a position/orientation change. A relative path that was
|
||||
// not associated with a host lookup should always trigger a history change (definitelyPathOnly) and a viewpointString
|
||||
// with a non empty pathString (suggesting this is the result of a lookup with the domain-server) that does not match
|
||||
// _newHostLookupPath should always trigger a history change.
|
||||
//
|
||||
// We use _newHostLookupPath to determine if the client has already stored its last address
|
||||
// before moving to a new host thanks to the information in the same lookup URL.
|
||||
|
||||
if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)) {
|
||||
addCurrentAddressToHistory(LookupTrigger::UserInput);
|
||||
}
|
||||
|
||||
if (!isNaN(newPosition.x) && !isNaN(newPosition.y) && !isNaN(newPosition.z)) {
|
||||
glm::quat newOrientation;
|
||||
|
@ -469,11 +533,11 @@ bool AddressManager::handleUsername(const QString& lookupString) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void AddressManager::setHost(const QString& host) {
|
||||
void AddressManager::setHost(const QString& host, LookupTrigger trigger) {
|
||||
if (host != _host) {
|
||||
|
||||
// if the host is being changed we should store current address in the history
|
||||
addCurrentAddressToHistory();
|
||||
addCurrentAddressToHistory(trigger);
|
||||
|
||||
_host = host;
|
||||
emit hostChanged(_host);
|
||||
|
@ -481,8 +545,8 @@ void AddressManager::setHost(const QString& host) {
|
|||
}
|
||||
|
||||
|
||||
void AddressManager::setDomainInfo(const QString& hostname, quint16 port) {
|
||||
setHost(hostname);
|
||||
void AddressManager::setDomainInfo(const QString& hostname, quint16 port, LookupTrigger trigger) {
|
||||
setHost(hostname, trigger);
|
||||
|
||||
_rootPlaceID = QUuid();
|
||||
|
||||
|
@ -495,11 +559,17 @@ void AddressManager::setDomainInfo(const QString& hostname, quint16 port) {
|
|||
|
||||
void AddressManager::goToUser(const QString& username) {
|
||||
QString formattedUsername = QUrl::toPercentEncoding(username);
|
||||
|
||||
// for history storage handling we remember how this lookup was trigged - for a username it's always user input
|
||||
QVariantMap requestParams;
|
||||
requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast<int>(LookupTrigger::UserInput));
|
||||
|
||||
// this is a username - pull the captured name and lookup that user's location
|
||||
AccountManager::getInstance().sendRequest(GET_USER_LOCATION.arg(formattedUsername),
|
||||
AccountManagerAuth::Optional,
|
||||
QNetworkAccessManager::GetOperation,
|
||||
apiCallbackParameters());
|
||||
apiCallbackParameters(),
|
||||
QByteArray(), nullptr, requestParams);
|
||||
}
|
||||
|
||||
void AddressManager::copyAddress() {
|
||||
|
@ -510,21 +580,36 @@ void AddressManager::copyPath() {
|
|||
QApplication::clipboard()->setText(currentPath());
|
||||
}
|
||||
|
||||
void AddressManager::addCurrentAddressToHistory() {
|
||||
if (_lastHistoryAppend == 0) {
|
||||
// we don't store the first address on application load
|
||||
// just update the last append time so the next is stored
|
||||
_lastHistoryAppend = usecTimestampNow();
|
||||
} else {
|
||||
const quint64 DOUBLE_STORE_THRESHOLD_USECS = 500000;
|
||||
void AddressManager::addCurrentAddressToHistory(LookupTrigger trigger) {
|
||||
|
||||
// avoid double storing when the host changes and the viewpoint changes immediately after
|
||||
if (usecTimestampNow() - _lastHistoryAppend > DOUBLE_STORE_THRESHOLD_USECS) {
|
||||
// add the current address to the history
|
||||
_history.append(currentAddress());
|
||||
// if we're cold starting and this is called for the first address (from settings) we don't do anything
|
||||
if (trigger != LookupTrigger::StartupFromSettings) {
|
||||
if (trigger == LookupTrigger::UserInput) {
|
||||
// anyime the user has manually looked up an address we know we should clear the forward stack
|
||||
_forwardStack.clear();
|
||||
|
||||
// change our last history append to now
|
||||
_lastHistoryAppend = usecTimestampNow();
|
||||
emit goForwardPossible(false);
|
||||
}
|
||||
|
||||
if (trigger == LookupTrigger::Back) {
|
||||
// we're about to push to the forward stack
|
||||
// if it's currently empty emit our signal to say that going forward is now possible
|
||||
if (_forwardStack.size() == 0) {
|
||||
emit goForwardPossible(true);
|
||||
}
|
||||
|
||||
// when the user is going back, we move the current address to the forward stack
|
||||
// and do not but it into the back stack
|
||||
_forwardStack.push(currentAddress());
|
||||
} else {
|
||||
// we're about to push to the back stack
|
||||
// if it's currently empty emit our signal to say that going forward is now possible
|
||||
if (_forwardStack.size() == 0) {
|
||||
emit goBackPossible(true);
|
||||
}
|
||||
|
||||
// unless this was triggered from the result of a named path lookup, add the current address to the history
|
||||
_backStack.push(currentAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
#ifndef hifi_AddressManager_h
|
||||
#define hifi_AddressManager_h
|
||||
|
||||
#include <qobject.h>
|
||||
#include <QSharedMemory>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QStack>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
@ -38,6 +38,14 @@ class AddressManager : public QObject, public Dependency {
|
|||
Q_PROPERTY(QString hostname READ getHost)
|
||||
Q_PROPERTY(QString pathname READ currentPath)
|
||||
public:
|
||||
|
||||
enum LookupTrigger {
|
||||
UserInput,
|
||||
Back,
|
||||
Forward,
|
||||
StartupFromSettings
|
||||
};
|
||||
|
||||
bool isConnected();
|
||||
const QString& getProtocol() { return HIFI_URL_SCHEME; };
|
||||
|
||||
|
@ -47,10 +55,7 @@ public:
|
|||
const QUuid& getRootPlaceID() const { return _rootPlaceID; }
|
||||
|
||||
const QString& getHost() const { return _host; }
|
||||
void setHost(const QString& host);
|
||||
|
||||
void attemptPlaceNameLookup(const QString& lookupString, const QString& overridePath = QString());
|
||||
void attemptDomainIDLookup(const QString& lookupString, const QString& overridePath = QString());
|
||||
|
||||
void setPositionGetter(PositionGetter positionGetter) { _positionGetter = positionGetter; }
|
||||
void setOrientationGetter(OrientationGetter orientationGetter) { _orientationGetter = orientationGetter; }
|
||||
|
@ -60,9 +65,14 @@ public:
|
|||
public slots:
|
||||
void handleLookupString(const QString& lookupString);
|
||||
|
||||
// we currently expect this to be called from NodeList once handleLookupString has been called with a path
|
||||
bool goToViewpointForPath(const QString& viewpointString, const QString& pathString)
|
||||
{ return handleViewpoint(viewpointString, false, false, pathString); }
|
||||
|
||||
void goBack();
|
||||
void goForward();
|
||||
|
||||
void goToUser(const QString& username);
|
||||
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply& reply);
|
||||
bool goToViewpoint(const QString& viewpointString) { return handleViewpoint(viewpointString); }
|
||||
|
||||
void storeCurrentAddress();
|
||||
|
||||
|
@ -73,40 +83,56 @@ signals:
|
|||
void lookupResultsFinished();
|
||||
void lookupResultIsOffline();
|
||||
void lookupResultIsNotFound();
|
||||
|
||||
void possibleDomainChangeRequired(const QString& newHostname, quint16 newPort);
|
||||
void possibleDomainChangeRequiredViaICEForID(const QString& iceServerHostname, const QUuid& domainID);
|
||||
|
||||
void locationChangeRequired(const glm::vec3& newPosition,
|
||||
bool hasOrientationChange, const glm::quat& newOrientation,
|
||||
bool shouldFaceLocation);
|
||||
void pathChangeRequired(const QString& newPath);
|
||||
void hostChanged(const QString& newHost);
|
||||
|
||||
void goBackPossible(bool isPossible);
|
||||
void goForwardPossible(bool isPossible);
|
||||
|
||||
protected:
|
||||
AddressManager();
|
||||
private slots:
|
||||
void handleAPIResponse(QNetworkReply& requestReply);
|
||||
void handleAPIError(QNetworkReply& errorReply);
|
||||
|
||||
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply& reply);
|
||||
private:
|
||||
void setDomainInfo(const QString& hostname, quint16 port);
|
||||
void setHost(const QString& host, LookupTrigger trigger);
|
||||
void setDomainInfo(const QString& hostname, quint16 port, LookupTrigger trigger);
|
||||
|
||||
const JSONCallbackParameters& apiCallbackParameters();
|
||||
|
||||
bool handleUrl(const QUrl& lookupUrl);
|
||||
bool handleUrl(const QUrl& lookupUrl, LookupTrigger trigger = UserInput);
|
||||
|
||||
bool handleNetworkAddress(const QString& lookupString);
|
||||
void handlePath(const QString& path);
|
||||
bool handleViewpoint(const QString& viewpointString, bool shouldFace = false);
|
||||
bool handleNetworkAddress(const QString& lookupString, LookupTrigger trigger);
|
||||
void handlePath(const QString& path, LookupTrigger trigger, bool wasPathOnly = false);
|
||||
bool handleViewpoint(const QString& viewpointString, bool shouldFace = false,
|
||||
bool definitelyPathOnly = false, const QString& pathString = QString());
|
||||
bool handleUsername(const QString& lookupString);
|
||||
bool handleDomainID(const QString& host);
|
||||
|
||||
void addCurrentAddressToHistory();
|
||||
void attemptPlaceNameLookup(const QString& lookupString, const QString& overridePath, LookupTrigger trigger);
|
||||
void attemptDomainIDLookup(const QString& lookupString, const QString& overridePath, LookupTrigger trigger);
|
||||
|
||||
void addCurrentAddressToHistory(LookupTrigger trigger);
|
||||
|
||||
QString _host;
|
||||
QUuid _rootPlaceID;
|
||||
PositionGetter _positionGetter;
|
||||
OrientationGetter _orientationGetter;
|
||||
|
||||
QList<QUrl> _history;
|
||||
quint64 _lastHistoryAppend = 0;
|
||||
QStack<QUrl> _backStack;
|
||||
QStack<QUrl> _forwardStack;
|
||||
quint64 _lastBackPush = 0;
|
||||
|
||||
QString _newHostLookupPath;
|
||||
};
|
||||
|
||||
#endif // hifi_AddressManager_h
|
||||
|
|
|
@ -467,7 +467,7 @@ void NodeList::handleDSPathQueryResponse(const QByteArray& packet) {
|
|||
QString viewpoint = QString::fromUtf8(currentPosition, numViewpointBytes);
|
||||
|
||||
// Hand it off to the AddressManager so it can handle it as a relative viewpoint
|
||||
if (DependencyManager::get<AddressManager>()->goToViewpoint(viewpoint)) {
|
||||
if (DependencyManager::get<AddressManager>()->goToViewpointForPath(viewpoint, pathQuery)) {
|
||||
qCDebug(networking) << "Going to viewpoint" << viewpoint << "which was the lookup result for path" << pathQuery;
|
||||
} else {
|
||||
qCDebug(networking) << "Could not go to viewpoint" << viewpoint
|
||||
|
|
|
@ -9,25 +9,25 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMutexLocker>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "GeometryCache.h"
|
||||
#include <GeometryUtil.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <OctreePacketData.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <PathUtils.h>
|
||||
#include <ProgramObject.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Camera.h"
|
||||
#include "world.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
#include "Environment.h"
|
||||
|
||||
#include "SkyFromSpace_vert.h"
|
||||
#include "SkyFromSpace_frag.h"
|
||||
#include "SkyFromAtmosphere_vert.h"
|
||||
#include "SkyFromAtmosphere_frag.h"
|
||||
|
||||
uint qHash(const HifiSockAddr& sockAddr) {
|
||||
if (sockAddr.getAddress().isNull()) {
|
||||
return 0; // shouldn't happen, but if it does, zero is a perfectly valid hash
|
||||
|
@ -42,20 +42,15 @@ Environment::Environment()
|
|||
}
|
||||
|
||||
Environment::~Environment() {
|
||||
if (_initialized) {
|
||||
delete _skyFromAtmosphereProgram;
|
||||
delete _skyFromSpaceProgram;
|
||||
}
|
||||
}
|
||||
|
||||
void Environment::init() {
|
||||
if (_initialized) {
|
||||
qCDebug(interfaceapp, "[ERROR] Environment is already initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
_skyFromAtmosphereProgram = createSkyProgram("Atmosphere", _skyFromAtmosphereUniformLocations);
|
||||
_skyFromSpaceProgram = createSkyProgram("Space", _skyFromSpaceUniformLocations);
|
||||
setupAtmosphereProgram(SkyFromSpace_vert, SkyFromSpace_frag, _skyFromSpaceProgram, _skyFromSpaceUniformLocations);
|
||||
setupAtmosphereProgram(SkyFromAtmosphere_vert, SkyFromAtmosphere_frag, _skyFromAtmosphereProgram, _skyFromAtmosphereUniformLocations);
|
||||
|
||||
// start off with a default-constructed environment data
|
||||
_data[HifiSockAddr()][0];
|
||||
|
@ -63,22 +58,60 @@ void Environment::init() {
|
|||
_initialized = true;
|
||||
}
|
||||
|
||||
void Environment::setupAtmosphereProgram(const char* vertSource, const char* fragSource, gpu::PipelinePointer& pipeline, int* locations) {
|
||||
|
||||
auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vertSource)));
|
||||
auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fragSource)));
|
||||
|
||||
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS));
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
state->setDepthTest(false);
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
||||
pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
|
||||
|
||||
locations[CAMERA_POS_LOCATION] = program->getUniforms().findLocation("v3CameraPos");
|
||||
locations[LIGHT_POS_LOCATION] = program->getUniforms().findLocation("v3LightPos");
|
||||
locations[INV_WAVELENGTH_LOCATION] = program->getUniforms().findLocation("v3InvWavelength");
|
||||
locations[CAMERA_HEIGHT2_LOCATION] = program->getUniforms().findLocation("fCameraHeight2");
|
||||
locations[OUTER_RADIUS_LOCATION] = program->getUniforms().findLocation("fOuterRadius");
|
||||
locations[OUTER_RADIUS2_LOCATION] = program->getUniforms().findLocation("fOuterRadius2");
|
||||
locations[INNER_RADIUS_LOCATION] = program->getUniforms().findLocation("fInnerRadius");
|
||||
locations[KR_ESUN_LOCATION] = program->getUniforms().findLocation("fKrESun");
|
||||
locations[KM_ESUN_LOCATION] = program->getUniforms().findLocation("fKmESun");
|
||||
locations[KR_4PI_LOCATION] = program->getUniforms().findLocation("fKr4PI");
|
||||
locations[KM_4PI_LOCATION] = program->getUniforms().findLocation("fKm4PI");
|
||||
locations[SCALE_LOCATION] = program->getUniforms().findLocation("fScale");
|
||||
locations[SCALE_DEPTH_LOCATION] = program->getUniforms().findLocation("fScaleDepth");
|
||||
locations[SCALE_OVER_SCALE_DEPTH_LOCATION] = program->getUniforms().findLocation("fScaleOverScaleDepth");
|
||||
locations[G_LOCATION] = program->getUniforms().findLocation("g");
|
||||
locations[G2_LOCATION] = program->getUniforms().findLocation("g2");
|
||||
}
|
||||
|
||||
void Environment::resetToDefault() {
|
||||
_data.clear();
|
||||
_data[HifiSockAddr()][0];
|
||||
}
|
||||
|
||||
void Environment::renderAtmospheres(ViewFrustum& camera) {
|
||||
void Environment::renderAtmospheres(gpu::Batch& batch, ViewFrustum& camera) {
|
||||
// get the lock for the duration of the call
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
if (_environmentIsOverridden) {
|
||||
renderAtmosphere(camera, _overrideData);
|
||||
renderAtmosphere(batch, camera, _overrideData);
|
||||
} else {
|
||||
foreach (const ServerData& serverData, _data) {
|
||||
// TODO: do something about EnvironmentData
|
||||
foreach (const EnvironmentData& environmentData, serverData) {
|
||||
renderAtmosphere(camera, environmentData);
|
||||
renderAtmosphere(batch, camera, environmentData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -201,87 +234,51 @@ int Environment::parseData(const HifiSockAddr& senderAddress, const QByteArray&
|
|||
return bytesRead;
|
||||
}
|
||||
|
||||
ProgramObject* Environment::createSkyProgram(const char* from, int* locations) {
|
||||
ProgramObject* program = new ProgramObject();
|
||||
QByteArray prefix = QString(PathUtils::resourcesPath() + "/shaders/SkyFrom" + from).toUtf8();
|
||||
program->addShaderFromSourceFile(QGLShader::Vertex, prefix + ".vert");
|
||||
program->addShaderFromSourceFile(QGLShader::Fragment, prefix + ".frag");
|
||||
program->link();
|
||||
|
||||
locations[CAMERA_POS_LOCATION] = program->uniformLocation("v3CameraPos");
|
||||
locations[LIGHT_POS_LOCATION] = program->uniformLocation("v3LightPos");
|
||||
locations[INV_WAVELENGTH_LOCATION] = program->uniformLocation("v3InvWavelength");
|
||||
locations[CAMERA_HEIGHT2_LOCATION] = program->uniformLocation("fCameraHeight2");
|
||||
locations[OUTER_RADIUS_LOCATION] = program->uniformLocation("fOuterRadius");
|
||||
locations[OUTER_RADIUS2_LOCATION] = program->uniformLocation("fOuterRadius2");
|
||||
locations[INNER_RADIUS_LOCATION] = program->uniformLocation("fInnerRadius");
|
||||
locations[KR_ESUN_LOCATION] = program->uniformLocation("fKrESun");
|
||||
locations[KM_ESUN_LOCATION] = program->uniformLocation("fKmESun");
|
||||
locations[KR_4PI_LOCATION] = program->uniformLocation("fKr4PI");
|
||||
locations[KM_4PI_LOCATION] = program->uniformLocation("fKm4PI");
|
||||
locations[SCALE_LOCATION] = program->uniformLocation("fScale");
|
||||
locations[SCALE_DEPTH_LOCATION] = program->uniformLocation("fScaleDepth");
|
||||
locations[SCALE_OVER_SCALE_DEPTH_LOCATION] = program->uniformLocation("fScaleOverScaleDepth");
|
||||
locations[G_LOCATION] = program->uniformLocation("g");
|
||||
locations[G2_LOCATION] = program->uniformLocation("g2");
|
||||
|
||||
return program;
|
||||
}
|
||||
void Environment::renderAtmosphere(gpu::Batch& batch, ViewFrustum& camera, const EnvironmentData& data) {
|
||||
|
||||
void Environment::renderAtmosphere(ViewFrustum& camera, const EnvironmentData& data) {
|
||||
glm::vec3 center = data.getAtmosphereCenter();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(center.x, center.y, center.z);
|
||||
Transform transform;
|
||||
transform.setTranslation(center);
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
glm::vec3 relativeCameraPos = camera.getPosition() - center;
|
||||
float height = glm::length(relativeCameraPos);
|
||||
|
||||
// use the appropriate shader depending on whether we're inside or outside
|
||||
ProgramObject* program;
|
||||
int* locations;
|
||||
if (height < data.getAtmosphereOuterRadius()) {
|
||||
program = _skyFromAtmosphereProgram;
|
||||
batch.setPipeline(_skyFromAtmosphereProgram);
|
||||
locations = _skyFromAtmosphereUniformLocations;
|
||||
|
||||
} else {
|
||||
program = _skyFromSpaceProgram;
|
||||
batch.setPipeline(_skyFromSpaceProgram);
|
||||
locations = _skyFromSpaceUniformLocations;
|
||||
}
|
||||
|
||||
// the constants here are from Sean O'Neil's GPU Gems entry
|
||||
// (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html), GameEngine.cpp
|
||||
program->bind();
|
||||
program->setUniform(locations[CAMERA_POS_LOCATION], relativeCameraPos);
|
||||
batch._glUniform3f(locations[CAMERA_POS_LOCATION], relativeCameraPos.x, relativeCameraPos.y, relativeCameraPos.z);
|
||||
glm::vec3 lightDirection = glm::normalize(data.getSunLocation());
|
||||
program->setUniform(locations[LIGHT_POS_LOCATION], lightDirection);
|
||||
program->setUniformValue(locations[INV_WAVELENGTH_LOCATION],
|
||||
1 / powf(data.getScatteringWavelengths().r, 4.0f),
|
||||
1 / powf(data.getScatteringWavelengths().g, 4.0f),
|
||||
1 / powf(data.getScatteringWavelengths().b, 4.0f));
|
||||
program->setUniformValue(locations[CAMERA_HEIGHT2_LOCATION], height * height);
|
||||
program->setUniformValue(locations[OUTER_RADIUS_LOCATION], data.getAtmosphereOuterRadius());
|
||||
program->setUniformValue(locations[OUTER_RADIUS2_LOCATION], data.getAtmosphereOuterRadius() * data.getAtmosphereOuterRadius());
|
||||
program->setUniformValue(locations[INNER_RADIUS_LOCATION], data.getAtmosphereInnerRadius());
|
||||
program->setUniformValue(locations[KR_ESUN_LOCATION], data.getRayleighScattering() * data.getSunBrightness());
|
||||
program->setUniformValue(locations[KM_ESUN_LOCATION], data.getMieScattering() * data.getSunBrightness());
|
||||
program->setUniformValue(locations[KR_4PI_LOCATION], data.getRayleighScattering() * 4.0f * PI);
|
||||
program->setUniformValue(locations[KM_4PI_LOCATION], data.getMieScattering() * 4.0f * PI);
|
||||
program->setUniformValue(locations[SCALE_LOCATION], 1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius()));
|
||||
program->setUniformValue(locations[SCALE_DEPTH_LOCATION], 0.25f);
|
||||
program->setUniformValue(locations[SCALE_OVER_SCALE_DEPTH_LOCATION],
|
||||
batch._glUniform3f(locations[LIGHT_POS_LOCATION], lightDirection.x, lightDirection.y, lightDirection.z);
|
||||
batch._glUniform3f(locations[INV_WAVELENGTH_LOCATION],
|
||||
1 / powf(data.getScatteringWavelengths().r, 4.0f),
|
||||
1 / powf(data.getScatteringWavelengths().g, 4.0f),
|
||||
1 / powf(data.getScatteringWavelengths().b, 4.0f));
|
||||
batch._glUniform1f(locations[CAMERA_HEIGHT2_LOCATION], height * height);
|
||||
batch._glUniform1f(locations[OUTER_RADIUS_LOCATION], data.getAtmosphereOuterRadius());
|
||||
batch._glUniform1f(locations[OUTER_RADIUS2_LOCATION], data.getAtmosphereOuterRadius() * data.getAtmosphereOuterRadius());
|
||||
batch._glUniform1f(locations[INNER_RADIUS_LOCATION], data.getAtmosphereInnerRadius());
|
||||
batch._glUniform1f(locations[KR_ESUN_LOCATION], data.getRayleighScattering() * data.getSunBrightness());
|
||||
batch._glUniform1f(locations[KM_ESUN_LOCATION], data.getMieScattering() * data.getSunBrightness());
|
||||
batch._glUniform1f(locations[KR_4PI_LOCATION], data.getRayleighScattering() * 4.0f * PI);
|
||||
batch._glUniform1f(locations[KM_4PI_LOCATION], data.getMieScattering() * 4.0f * PI);
|
||||
batch._glUniform1f(locations[SCALE_LOCATION], 1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius()));
|
||||
batch._glUniform1f(locations[SCALE_DEPTH_LOCATION], 0.25f);
|
||||
batch._glUniform1f(locations[SCALE_OVER_SCALE_DEPTH_LOCATION],
|
||||
(1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius())) / 0.25f);
|
||||
program->setUniformValue(locations[G_LOCATION], -0.990f);
|
||||
program->setUniformValue(locations[G2_LOCATION], -0.990f * -0.990f);
|
||||
batch._glUniform1f(locations[G_LOCATION], -0.990f);
|
||||
batch._glUniform1f(locations[G2_LOCATION], -0.990f * -0.990f);
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(1.0f, 100, 50, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); //Draw a unit sphere
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
program->release();
|
||||
|
||||
glPopMatrix();
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(batch,1.0f, 100, 50, glm::vec4(1.0f, 0.0f, 0.0f, 0.5f)); //Draw a unit sphere
|
||||
}
|
|
@ -16,8 +16,9 @@
|
|||
#include <QMutex>
|
||||
|
||||
#include <HifiSockAddr.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include "EnvironmentData.h"
|
||||
#include <EnvironmentData.h>
|
||||
|
||||
class ViewFrustum;
|
||||
class ProgramObject;
|
||||
|
@ -29,7 +30,7 @@ public:
|
|||
|
||||
void init();
|
||||
void resetToDefault();
|
||||
void renderAtmospheres(ViewFrustum& camera);
|
||||
void renderAtmospheres(gpu::Batch& batch, ViewFrustum& camera);
|
||||
|
||||
void override(const EnvironmentData& overrideData) { _overrideData = overrideData; _environmentIsOverridden = true; }
|
||||
void endOverride() { _environmentIsOverridden = false; }
|
||||
|
@ -44,14 +45,10 @@ private:
|
|||
bool findCapsulePenetration(const glm::vec3& start,
|
||||
const glm::vec3& end, float radius, glm::vec3& penetration); // NOTE: Deprecated
|
||||
|
||||
ProgramObject* createSkyProgram(const char* from, int* locations);
|
||||
|
||||
void renderAtmosphere(ViewFrustum& camera, const EnvironmentData& data);
|
||||
void renderAtmosphere(gpu::Batch& batch, ViewFrustum& camera, const EnvironmentData& data);
|
||||
|
||||
bool _initialized;
|
||||
ProgramObject* _skyFromAtmosphereProgram;
|
||||
ProgramObject* _skyFromSpaceProgram;
|
||||
|
||||
|
||||
enum {
|
||||
CAMERA_POS_LOCATION,
|
||||
LIGHT_POS_LOCATION,
|
||||
|
@ -72,6 +69,11 @@ private:
|
|||
LOCATION_COUNT
|
||||
};
|
||||
|
||||
void setupAtmosphereProgram(const char* vertSource, const char* fragSource, gpu::PipelinePointer& pipelineProgram, int* locations);
|
||||
|
||||
|
||||
gpu::PipelinePointer _skyFromAtmosphereProgram;
|
||||
gpu::PipelinePointer _skyFromSpaceProgram;
|
||||
int _skyFromAtmosphereUniformLocations[LOCATION_COUNT];
|
||||
int _skyFromSpaceUniformLocations[LOCATION_COUNT];
|
||||
|
|
@ -82,6 +82,7 @@ Model::Model(QObject* parent) :
|
|||
_isVisible(true),
|
||||
_blendNumber(0),
|
||||
_appliedBlendNumber(0),
|
||||
_calculatedMeshPartOffsetValid(false),
|
||||
_calculatedMeshPartBoxesValid(false),
|
||||
_calculatedMeshBoxesValid(false),
|
||||
_calculatedMeshTrianglesValid(false),
|
||||
|
@ -544,6 +545,10 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
// we can use the AABox's ray intersection by mapping our origin and direction into the model frame
|
||||
// and testing intersection there.
|
||||
if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) {
|
||||
|
||||
if (!_calculatedMeshBoxesValid) {
|
||||
recalculateMeshBoxes(pickAgainstTriangles);
|
||||
}
|
||||
|
||||
float bestDistance = std::numeric_limits<float>::max();
|
||||
|
||||
|
@ -660,6 +665,25 @@ bool Model::convexHullContains(glm::vec3 point) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Model::recalculateMeshPartOffsets() {
|
||||
if (!_calculatedMeshPartOffsetValid) {
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
int numberOfMeshes = geometry.meshes.size();
|
||||
_calculatedMeshPartOffset.clear();
|
||||
for (int i = 0; i < numberOfMeshes; i++) {
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
qint64 partOffset = 0;
|
||||
for (int j = 0; j < mesh.parts.size(); j++) {
|
||||
const FBXMeshPart& part = mesh.parts.at(j);
|
||||
_calculatedMeshPartOffset[QPair<int,int>(i, j)] = partOffset;
|
||||
partOffset += part.quadIndices.size() * sizeof(int);
|
||||
partOffset += part.triangleIndices.size() * sizeof(int);
|
||||
|
||||
}
|
||||
}
|
||||
_calculatedMeshPartOffsetValid = true;
|
||||
}
|
||||
}
|
||||
// TODO: we seem to call this too often when things haven't actually changed... look into optimizing this
|
||||
// Any script might trigger findRayIntersectionAgainstSubMeshes (and maybe convexHullContains), so these
|
||||
// can occur multiple times. In addition, rendering does it's own ray picking in order to decide which
|
||||
|
@ -675,7 +699,8 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
|||
_calculatedMeshTriangles.clear();
|
||||
_calculatedMeshTriangles.resize(numberOfMeshes);
|
||||
_calculatedMeshPartBoxes.clear();
|
||||
_calculatedMeshPartOffet.clear();
|
||||
_calculatedMeshPartOffset.clear();
|
||||
_calculatedMeshPartOffsetValid = false;
|
||||
for (int i = 0; i < numberOfMeshes; i++) {
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents);
|
||||
|
@ -770,7 +795,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
|||
}
|
||||
}
|
||||
_calculatedMeshPartBoxes[QPair<int,int>(i, j)] = thisPartBounds;
|
||||
_calculatedMeshPartOffet[QPair<int,int>(i, j)] = partOffset;
|
||||
_calculatedMeshPartOffset[QPair<int,int>(i, j)] = partOffset;
|
||||
|
||||
partOffset += part.quadIndices.size() * sizeof(int);
|
||||
partOffset += part.triangleIndices.size() * sizeof(int);
|
||||
|
@ -778,6 +803,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
|||
}
|
||||
_calculatedMeshTriangles[i] = thisMeshTriangles;
|
||||
_calculatedMeshPartBoxesValid = true;
|
||||
_calculatedMeshPartOffsetValid = true;
|
||||
}
|
||||
}
|
||||
_calculatedMeshBoxesValid = true;
|
||||
|
@ -786,16 +812,6 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
|||
}
|
||||
|
||||
void Model::renderSetup(RenderArgs* args) {
|
||||
// if we don't have valid mesh boxes, calculate them now, this only matters in cases
|
||||
// where our caller has passed RenderArgs which will include a view frustum we can cull
|
||||
// against. We cache the results of these calculations so long as the model hasn't been
|
||||
// simulated and the mesh hasn't changed.
|
||||
if (args && !_calculatedMeshBoxesValid) {
|
||||
_mutex.lock();
|
||||
recalculateMeshBoxes();
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
// set up dilated textures on first render after load/simulate
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
if (_dilatedTextures.isEmpty()) {
|
||||
|
@ -1342,18 +1358,15 @@ void Model::snapToRegistrationPoint() {
|
|||
}
|
||||
|
||||
void Model::simulate(float deltaTime, bool fullUpdate) {
|
||||
/*
|
||||
qDebug() << "Model::simulate()";
|
||||
qDebug() << " _translation:" << _translation;
|
||||
qDebug() << " _rotation:" << _rotation;
|
||||
*/
|
||||
|
||||
fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit)
|
||||
|| (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint);
|
||||
|
||||
if (isActive() && fullUpdate) {
|
||||
// NOTE: this seems problematic... need to review
|
||||
_calculatedMeshBoxesValid = false; // if we have to simulate, we need to assume our mesh boxes are all invalid
|
||||
// NOTE: This is overly aggressive and we are invalidating the MeshBoxes when in fact they may not be invalid
|
||||
// they really only become invalid if something about the transform to world space has changed. This is
|
||||
// not too bad at this point, because it doesn't impact rendering. However it does slow down ray picking
|
||||
// because ray picking needs valid boxes to work
|
||||
_calculatedMeshBoxesValid = false;
|
||||
_calculatedMeshTrianglesValid = false;
|
||||
|
||||
// check for scale to fit
|
||||
|
@ -1761,11 +1774,31 @@ void Model::setupBatchTransform(gpu::Batch& batch, RenderArgs* args) {
|
|||
}
|
||||
|
||||
AABox Model::getPartBounds(int meshIndex, int partIndex) {
|
||||
if (!_calculatedMeshPartBoxesValid) {
|
||||
recalculateMeshBoxes(true);
|
||||
if (meshIndex < _meshStates.size()) {
|
||||
const MeshState& state = _meshStates.at(meshIndex);
|
||||
bool isSkinned = state.clusterMatrices.size() > 1;
|
||||
if (isSkinned) {
|
||||
// if we're skinned return the entire mesh extents because we can't know for sure our clusters don't move us
|
||||
return calculateScaledOffsetAABox(_geometry->getFBXGeometry().meshExtents);
|
||||
}
|
||||
}
|
||||
if (_calculatedMeshPartBoxesValid && _calculatedMeshPartBoxes.contains(QPair<int,int>(meshIndex, partIndex))) {
|
||||
return calculateScaledOffsetAABox(_calculatedMeshPartBoxes[QPair<int,int>(meshIndex, partIndex)]);
|
||||
|
||||
if (_geometry->getFBXGeometry().meshes.size() > meshIndex) {
|
||||
|
||||
// FIX ME! - This is currently a hack because for some mesh parts our efforts to calculate the bounding
|
||||
// box of the mesh part fails. It seems to create boxes that are not consistent with where the
|
||||
// geometry actually renders. If instead we make all the parts share the bounds of the entire subMesh
|
||||
// things will render properly.
|
||||
//
|
||||
// return calculateScaledOffsetAABox(_calculatedMeshPartBoxes[QPair<int,int>(meshIndex, partIndex)]);
|
||||
//
|
||||
// NOTE: we also don't want to use the _calculatedMeshBoxes[] because they don't handle avatar moving correctly
|
||||
// without recalculating them...
|
||||
// return _calculatedMeshBoxes[meshIndex];
|
||||
//
|
||||
// If we not skinned use the bounds of the subMesh for all it's parts
|
||||
const FBXMesh& mesh = _geometry->getFBXGeometry().meshes.at(meshIndex);
|
||||
return calculateScaledOffsetExtents(mesh.meshExtents);
|
||||
}
|
||||
return AABox();
|
||||
}
|
||||
|
@ -1775,29 +1808,15 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
|
|||
return; // bail asap
|
||||
}
|
||||
|
||||
// we always need these properly calculated before we can render, this will likely already have been done
|
||||
// since the engine will call our getPartBounds() before rendering us.
|
||||
if (!_calculatedMeshPartBoxesValid) {
|
||||
recalculateMeshBoxes(true);
|
||||
// We need to make sure we have valid offsets calculated before we can render
|
||||
if (!_calculatedMeshPartOffsetValid) {
|
||||
recalculateMeshPartOffsets();
|
||||
}
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
auto mode = args->_renderMode;
|
||||
|
||||
// render the part bounding box
|
||||
#ifdef DEBUG_BOUNDING_PARTS
|
||||
{
|
||||
glm::vec4 cubeColor(1.0f,0.0f,0.0f,1.0f);
|
||||
AABox partBounds = getPartBounds(meshIndex, partIndex);
|
||||
|
||||
glm::mat4 translation = glm::translate(partBounds.calcCenter());
|
||||
glm::mat4 scale = glm::scale(partBounds.getDimensions());
|
||||
glm::mat4 modelToWorldMatrix = translation * scale;
|
||||
batch.setModelTransform(modelToWorldMatrix);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(batch, 1.0f, cubeColor);
|
||||
}
|
||||
#endif //def DEBUG_BOUNDING_PARTS
|
||||
|
||||
// Capture the view matrix once for the rendering of this model
|
||||
if (_transforms.empty()) {
|
||||
|
@ -1824,6 +1843,29 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
|
|||
bool hasLightmap = mesh.hasEmissiveTexture();
|
||||
bool isSkinned = state.clusterMatrices.size() > 1;
|
||||
bool wireframe = isWireframe();
|
||||
|
||||
// render the part bounding box
|
||||
#ifdef DEBUG_BOUNDING_PARTS
|
||||
{
|
||||
AABox partBounds = getPartBounds(meshIndex, partIndex);
|
||||
bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE;
|
||||
|
||||
glm::vec4 cubeColor;
|
||||
if (isSkinned) {
|
||||
cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f);
|
||||
} else if (inView) {
|
||||
cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f);
|
||||
} else {
|
||||
cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
Transform transform;
|
||||
transform.setTranslation(partBounds.calcCenter());
|
||||
transform.setScale(partBounds.getDimensions());
|
||||
batch.setModelTransform(transform);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(batch, 1.0f, cubeColor);
|
||||
}
|
||||
#endif //def DEBUG_BOUNDING_PARTS
|
||||
|
||||
if (wireframe) {
|
||||
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||
|
@ -1976,8 +2018,8 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
|
|||
}
|
||||
}
|
||||
|
||||
qint64 offset = _calculatedMeshPartOffet[QPair<int,int>(meshIndex, partIndex)];
|
||||
|
||||
qint64 offset = _calculatedMeshPartOffset[QPair<int,int>(meshIndex, partIndex)];
|
||||
|
||||
if (part.quadIndices.size() > 0) {
|
||||
batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset);
|
||||
offset += part.quadIndices.size() * sizeof(int);
|
||||
|
@ -2047,6 +2089,9 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f
|
|||
Locations*& locations) {
|
||||
|
||||
RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe);
|
||||
if (mode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
key = RenderKey(key.getRaw() | RenderKey::IS_MIRROR);
|
||||
}
|
||||
auto pipeline = _renderPipelineLib.find(key.getRaw());
|
||||
if (pipeline == _renderPipelineLib.end()) {
|
||||
qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw();
|
||||
|
|
|
@ -369,7 +369,8 @@ private:
|
|||
};
|
||||
|
||||
QHash<QPair<int,int>, AABox> _calculatedMeshPartBoxes; // world coordinate AABoxes for all sub mesh part boxes
|
||||
QHash<QPair<int,int>, qint64> _calculatedMeshPartOffet;
|
||||
QHash<QPair<int,int>, qint64> _calculatedMeshPartOffset;
|
||||
bool _calculatedMeshPartOffsetValid;
|
||||
|
||||
|
||||
bool _calculatedMeshPartBoxesValid;
|
||||
|
@ -381,6 +382,7 @@ private:
|
|||
QMutex _mutex;
|
||||
|
||||
void recalculateMeshBoxes(bool pickAgainstTriangles = false);
|
||||
void recalculateMeshPartOffsets();
|
||||
|
||||
void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes
|
||||
|
||||
|
|
|
@ -15,9 +15,12 @@
|
|||
#include "DeferredLightingEffect.h"
|
||||
#include "ViewFrustum.h"
|
||||
#include "RenderArgs.h"
|
||||
#include "TextureCache.h"
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "overlay3D_vert.h"
|
||||
#include "overlay3D_frag.h"
|
||||
|
||||
using namespace render;
|
||||
|
||||
|
@ -50,7 +53,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
|||
_jobs.push_back(Job(RenderDeferred()));
|
||||
_jobs.push_back(Job(ResolveDeferred()));
|
||||
_jobs.push_back(Job(DrawTransparentDeferred()));
|
||||
_jobs.push_back(Job(DrawPostLayered()));
|
||||
_jobs.push_back(Job(DrawOverlay3D()));
|
||||
_jobs.push_back(Job(ResetGLState()));
|
||||
}
|
||||
|
||||
|
@ -136,10 +139,12 @@ template <> void render::jobRun(const DrawOpaqueDeferred& job, const SceneContex
|
|||
Transform viewMat;
|
||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||
args->_viewFrustum->evalViewTransform(viewMat);
|
||||
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
renderContext->args->_renderMode = RenderArgs::NORMAL_RENDER_MODE;
|
||||
{
|
||||
GLenum buffers[3];
|
||||
int bufferCount = 0;
|
||||
|
@ -204,11 +209,12 @@ template <> void render::jobRun(const DrawTransparentDeferred& job, const SceneC
|
|||
Transform viewMat;
|
||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||
args->_viewFrustum->evalViewTransform(viewMat);
|
||||
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
args->_renderMode = RenderArgs::NORMAL_RENDER_MODE;
|
||||
|
||||
const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
|
||||
|
||||
{
|
||||
|
@ -222,10 +228,76 @@ template <> void render::jobRun(const DrawTransparentDeferred& job, const SceneC
|
|||
|
||||
renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems);
|
||||
|
||||
// Before rendering the batch make sure we re in sync with gl state
|
||||
args->_context->syncCache();
|
||||
args->_context->render((*args->_batch));
|
||||
args->_batch = nullptr;
|
||||
|
||||
// reset blend function to standard...
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
// glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
}
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const {
|
||||
if (!_opaquePipeline) {
|
||||
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert)));
|
||||
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag)));
|
||||
|
||||
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
|
||||
|
||||
auto state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
|
||||
_opaquePipeline.reset(gpu::Pipeline::create(program, state));
|
||||
}
|
||||
return _opaquePipeline;
|
||||
}
|
||||
|
||||
template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
PerformanceTimer perfTimer("DrawOverlay3D");
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
|
||||
// render backgrounds
|
||||
auto& scene = sceneContext->_scene;
|
||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withLayered());
|
||||
|
||||
|
||||
ItemIDsBounds inItems;
|
||||
inItems.reserve(items.size());
|
||||
for (auto id : items) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (item.getKey().isVisible() && (item.getLayer() == 1)) {
|
||||
inItems.emplace_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
gpu::Batch batch;
|
||||
args->_batch = &batch;
|
||||
args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture();
|
||||
|
||||
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||
args->_viewFrustum->evalViewTransform(viewMat);
|
||||
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
batch.setPipeline(job.getOpaquePipeline());
|
||||
batch.setUniformTexture(0, args->_whiteTexture);
|
||||
|
||||
if (!inItems.empty()) {
|
||||
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0);
|
||||
renderItems(sceneContext, renderContext, inItems);
|
||||
}
|
||||
|
||||
// Before rendering the batch make sure we re in sync with gl state
|
||||
args->_context->syncCache();
|
||||
args->_context->render((*args->_batch));
|
||||
args->_batch = nullptr;
|
||||
args->_whiteTexture.reset();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "render/DrawTask.h"
|
||||
|
||||
#include "gpu/Pipeline.h"
|
||||
|
||||
class PrepareDeferred {
|
||||
public:
|
||||
};
|
||||
|
@ -50,6 +52,15 @@ namespace render {
|
|||
template <> void jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
|
||||
}
|
||||
|
||||
class DrawOverlay3D {
|
||||
mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
|
||||
public:
|
||||
const gpu::PipelinePointer& getOpaquePipeline() const;
|
||||
};
|
||||
namespace render {
|
||||
template <> void jobRun(const DrawOverlay3D& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
|
||||
}
|
||||
|
||||
class RenderDeferredTask : public render::Task {
|
||||
public:
|
||||
|
||||
|
|
|
@ -53,12 +53,14 @@ uniform float g2;
|
|||
|
||||
varying vec3 position;
|
||||
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
|
||||
void main (void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
|
@ -102,7 +104,8 @@ void main (void)
|
|||
|
||||
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
gl_FragColor.rgb = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0/2.2));
|
||||
|
||||
vec3 finalColor = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb;
|
||||
gl_FragColor.a = finalColor.b;
|
||||
gl_FragColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2));
|
||||
}
|
|
@ -33,6 +33,9 @@
|
|||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3LightPos; // The direction vector to the light source
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
|
@ -52,17 +55,14 @@ const float fSamples = 2.0;
|
|||
|
||||
varying vec3 position;
|
||||
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
position = gl_Vertex.xyz * fOuterRadius;
|
||||
|
||||
gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0);
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
vec4 v4pos = vec4(position, 1.0);
|
||||
<$transformModelToClipPos(cam, obj, v4pos, gl_Position)$>
|
||||
}
|
|
@ -108,7 +108,8 @@ void main (void)
|
|||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
vec3 color = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 secondaryColor = v3FrontColor * fKmESun;
|
||||
gl_FragColor.rgb = color + fMiePhase * secondaryColor;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0/2.2));
|
||||
|
||||
vec3 finalColor = color + fMiePhase * secondaryColor;
|
||||
gl_FragColor.a = finalColor.b;
|
||||
gl_FragColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2));
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#version 120
|
||||
|
||||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
|
@ -32,12 +33,20 @@
|
|||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
uniform float fOuterRadius; // The outer (atmosphere) radius
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
||||
void main(void) {
|
||||
position = gl_Vertex.xyz * fOuterRadius;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0);
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
vec4 v4pos = vec4(position, 1.0);
|
||||
<$transformModelToClipPos(cam, obj, v4pos, gl_Position)$>
|
||||
}
|
|
@ -101,7 +101,7 @@ struct QuadBuilder {
|
|||
texMin);
|
||||
}
|
||||
QuadBuilder(const Glyph3D& glyph, const glm::vec2& offset) :
|
||||
QuadBuilder(offset + glyph.offset - glm::vec2(0.0f, glyph.size.y), glyph.size,
|
||||
QuadBuilder(offset + glm::vec2(glyph.offset.x, glyph.offset.y - glyph.size.y), glyph.size,
|
||||
glyph.texOffset, glyph.texSize) {}
|
||||
|
||||
};
|
||||
|
@ -113,7 +113,7 @@ public:
|
|||
void read(QIODevice& path);
|
||||
|
||||
glm::vec2 computeExtent(const QString& str) const;
|
||||
float getRowHeight() const { return _rowHeight; }
|
||||
float getFontSize() const { return _fontSize; }
|
||||
|
||||
// Render string to batch
|
||||
void drawString(gpu::Batch& batch, float x, float y, const QString& str,
|
||||
|
@ -139,7 +139,6 @@ private:
|
|||
// Font characteristics
|
||||
QString _family;
|
||||
float _fontSize = 0.0f;
|
||||
float _rowHeight = 0.0f;
|
||||
float _leading = 0.0f;
|
||||
float _ascent = 0.0f;
|
||||
float _descent = 0.0f;
|
||||
|
@ -251,13 +250,14 @@ glm::vec2 Font3D::computeTokenExtent(const QString& token) const {
|
|||
glm::vec2 Font3D::computeExtent(const QString& str) const {
|
||||
glm::vec2 extent = glm::vec2(0.0f, 0.0f);
|
||||
|
||||
QStringList tokens = splitLines(str);
|
||||
foreach(const QString& token, tokens) {
|
||||
glm::vec2 tokenExtent = computeTokenExtent(token);
|
||||
extent.x = std::max(tokenExtent.x, extent.x);
|
||||
QStringList lines{ splitLines(str) };
|
||||
if (!lines.empty()) {
|
||||
for(const auto& line : lines) {
|
||||
glm::vec2 tokenExtent = computeTokenExtent(line);
|
||||
extent.x = std::max(tokenExtent.x, extent.x);
|
||||
}
|
||||
extent.y = lines.count() * _fontSize;
|
||||
}
|
||||
extent.y = tokens.count() * _rowHeight;
|
||||
|
||||
return extent;
|
||||
}
|
||||
|
||||
|
@ -288,8 +288,7 @@ void Font3D::read(QIODevice& in) {
|
|||
readStream(in, _descent);
|
||||
readStream(in, _spaceWidth);
|
||||
_fontSize = _ascent + _descent;
|
||||
_rowHeight = _fontSize + _leading;
|
||||
|
||||
|
||||
// Read character count
|
||||
uint16_t count;
|
||||
readStream(in, count);
|
||||
|
@ -393,7 +392,7 @@ void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str,
|
|||
}
|
||||
if (isNewLine || forceNewLine) {
|
||||
// Character return, move the advance to a new line
|
||||
advance = glm::vec2(x, advance.y - _rowHeight);
|
||||
advance = glm::vec2(x, advance.y - _leading);
|
||||
|
||||
if (isNewLine) {
|
||||
// No need to draw anything, go directly to next token
|
||||
|
@ -413,7 +412,7 @@ void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str,
|
|||
for (auto c : token) {
|
||||
auto glyph = _glyphs[c];
|
||||
|
||||
QuadBuilder qd(glyph, advance - glm::vec2(0.0f, _fontSize));
|
||||
QuadBuilder qd(glyph, advance - glm::vec2(0.0f, _ascent));
|
||||
_verticesBuffer->append(sizeof(QuadBuilder), (const gpu::Byte*)&qd);
|
||||
_numVertices += 4;
|
||||
|
||||
|
@ -477,9 +476,9 @@ glm::vec2 TextRenderer3D::computeExtent(const QString& str) const {
|
|||
return glm::vec2(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
float TextRenderer3D::getRowHeight() const {
|
||||
float TextRenderer3D::getFontSize() const {
|
||||
if (_font) {
|
||||
return _font->getRowHeight();
|
||||
return _font->getFontSize();
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
~TextRenderer3D();
|
||||
|
||||
glm::vec2 computeExtent(const QString& str) const;
|
||||
float getRowHeight() const;
|
||||
float getFontSize() const;
|
||||
|
||||
void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color = glm::vec4(-1.0f),
|
||||
const glm::vec2& bounds = glm::vec2(-1.0f));
|
||||
|
|
29
libraries/render-utils/src/overlay3D.slf
Normal file
29
libraries/render-utils/src/overlay3D.slf
Normal file
|
@ -0,0 +1,29 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// model.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 6/16/15.
|
||||
// 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 diffuseMap;
|
||||
|
||||
varying vec2 varTexcoord;
|
||||
|
||||
varying vec3 varEyeNormal;
|
||||
|
||||
varying vec4 varColor;
|
||||
|
||||
|
||||
void main(void) {
|
||||
vec4 diffuse = texture2D(diffuseMap, varTexcoord.st);
|
||||
if (diffuse.a < 0.5) {
|
||||
discard;
|
||||
}
|
||||
gl_FragColor = vec4(varColor * diffuse);
|
||||
}
|
40
libraries/render-utils/src/overlay3D.slv
Normal file
40
libraries/render-utils/src/overlay3D.slv
Normal file
|
@ -0,0 +1,40 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// overlay3D.slv
|
||||
//
|
||||
// Created by Sam Gateau on 6/16/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
//attribute vec2 texcoord;
|
||||
|
||||
varying vec2 varTexcoord;
|
||||
|
||||
// interpolated eye position
|
||||
varying vec4 varEyePosition;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec3 varEyeNormal;
|
||||
|
||||
varying vec4 varColor;
|
||||
|
||||
void main(void) {
|
||||
varTexcoord = gl_MultiTexCoord0.xy;
|
||||
|
||||
// pass along the color
|
||||
varColor = gl_Color;
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToEyeAndClipPos(cam, obj, gl_Vertex, varEyePosition, gl_Position)$>
|
||||
<$transformModelToEyeDir(cam, obj, gl_Normal, varEyeNormal.xyz)$>
|
||||
}
|
|
@ -263,7 +263,6 @@ template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer
|
|||
|
||||
renderContext->_numDrawnOpaqueItems = renderedItems.size();
|
||||
|
||||
|
||||
ItemIDsBounds sortedItems;
|
||||
sortedItems.reserve(culledItems.size());
|
||||
if (renderContext->_sortOpaque) {
|
||||
|
@ -280,10 +279,12 @@ template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer
|
|||
Transform viewMat;
|
||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||
args->_viewFrustum->evalViewTransform(viewMat);
|
||||
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
renderContext->args->_renderMode = RenderArgs::NORMAL_RENDER_MODE;
|
||||
{
|
||||
GLenum buffers[3];
|
||||
int bufferCount = 0;
|
||||
|
@ -347,11 +348,12 @@ template <> void render::jobRun(const DrawTransparent& job, const SceneContextPo
|
|||
Transform viewMat;
|
||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||
args->_viewFrustum->evalViewTransform(viewMat);
|
||||
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
args->_renderMode = RenderArgs::NORMAL_RENDER_MODE;
|
||||
|
||||
const float MOSTLY_OPAQUE_THRESHOLD = 0.75f;
|
||||
const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
|
||||
|
||||
|
@ -434,6 +436,9 @@ template <> void render::jobRun(const DrawBackground& job, const SceneContextPoi
|
|||
Transform viewMat;
|
||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||
args->_viewFrustum->evalViewTransform(viewMat);
|
||||
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
|
@ -475,6 +480,9 @@ template <> void render::jobRun(const DrawPostLayered& job, const SceneContextPo
|
|||
Transform viewMat;
|
||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||
args->_viewFrustum->evalViewTransform(viewMat);
|
||||
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ signals:
|
|||
void mutedByMixer();
|
||||
void environmentMuted();
|
||||
void receivedFirstPacket();
|
||||
void disconnected();
|
||||
|
||||
private:
|
||||
AudioScriptingInterface();
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#define hifi_RenderArgs_h
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
|
||||
class AABox;
|
||||
class OctreeRenderer;
|
||||
|
@ -20,6 +22,7 @@ class ViewFrustum;
|
|||
namespace gpu {
|
||||
class Batch;
|
||||
class Context;
|
||||
class Texture;
|
||||
}
|
||||
|
||||
class RenderDetails {
|
||||
|
@ -109,6 +112,8 @@ public:
|
|||
gpu::Batch* _batch = nullptr;
|
||||
ShoudRenderFunctor _shouldRender;
|
||||
|
||||
std::shared_ptr<gpu::Texture> _whiteTexture;
|
||||
|
||||
RenderDetails _details;
|
||||
|
||||
float _alphaThreshold = 0.5f;
|
||||
|
|
92
libraries/ui/src/CursorManager.cpp
Normal file
92
libraries/ui/src/CursorManager.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/06/08
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "CursorManager.h"
|
||||
|
||||
#include <QCursor>
|
||||
#include <QWidget>
|
||||
#include <QUrl>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
namespace Cursor {
|
||||
|
||||
void Instance::setIcon(uint16_t icon) {
|
||||
_icon = icon;
|
||||
}
|
||||
|
||||
uint16_t Instance::getIcon() const {
|
||||
return _icon;
|
||||
}
|
||||
|
||||
|
||||
class MouseInstance : public Instance {
|
||||
Source getType() const {
|
||||
return Source::MOUSE;
|
||||
}
|
||||
|
||||
ivec2 getScreenPosition() const {
|
||||
return toGlm(QCursor::pos());
|
||||
}
|
||||
|
||||
ivec2 getWindowPosition(QWidget* widget) const {
|
||||
return toGlm(widget->mapFromGlobal(QCursor::pos()));
|
||||
}
|
||||
|
||||
vec2 getRelativePosition(QWidget* widget) const {
|
||||
vec2 pos = getWindowPosition(widget);
|
||||
pos /= vec2(toGlm(widget->size()));
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
|
||||
static QMap<uint16_t, QString> ICONS;
|
||||
static uint16_t _customIconId = Icon::USER_BASE;
|
||||
|
||||
Manager::Manager() {
|
||||
ICONS[Icon::DEFAULT] = PathUtils::resourcesPath() + "images/arrow.png";
|
||||
ICONS[Icon::LINK] = PathUtils::resourcesPath() + "images/reticleLink.png";
|
||||
}
|
||||
|
||||
Manager& Manager::instance() {
|
||||
static Manager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
uint8_t Manager::getCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
Instance* Manager::getCursor(uint8_t index) {
|
||||
Q_ASSERT(index < getCount());
|
||||
static MouseInstance mouseInstance;
|
||||
if (index == 0) {
|
||||
return &mouseInstance;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint16_t Manager::registerIcon(const QString& path) {
|
||||
ICONS[_customIconId] = path;
|
||||
return _customIconId++;
|
||||
}
|
||||
|
||||
const QString& Manager::getIconImage(uint16_t icon) {
|
||||
Q_ASSERT(ICONS.count(icon));
|
||||
return ICONS[icon];
|
||||
}
|
||||
|
||||
float Manager::getScale() {
|
||||
return _scale;
|
||||
}
|
||||
|
||||
void Manager::setScale(float scale) {
|
||||
_scale = scale;
|
||||
}
|
||||
|
||||
}
|
61
libraries/ui/src/CursorManager.h
Normal file
61
libraries/ui/src/CursorManager.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/06/08
|
||||
// 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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
namespace Cursor {
|
||||
enum class Source {
|
||||
MOUSE,
|
||||
LEFT_HAND,
|
||||
RIGHT_HAND,
|
||||
UNKNOWN,
|
||||
};
|
||||
|
||||
enum Icon {
|
||||
DEFAULT,
|
||||
LINK,
|
||||
GRAB,
|
||||
|
||||
// Add new system cursors here
|
||||
|
||||
// User cursors will have ids over this value
|
||||
USER_BASE = 0xFF,
|
||||
};
|
||||
|
||||
class Instance {
|
||||
public:
|
||||
virtual Source getType() const = 0;
|
||||
virtual ivec2 getWindowPosition(QWidget* widget) const = 0;
|
||||
virtual vec2 getRelativePosition(QWidget* widget) const = 0;
|
||||
virtual ivec2 getScreenPosition() const = 0;
|
||||
virtual void setIcon(uint16_t icon);
|
||||
virtual uint16_t getIcon() const;
|
||||
private:
|
||||
uint16_t _icon;
|
||||
};
|
||||
|
||||
class Manager {
|
||||
Manager();
|
||||
Manager(const Manager& other) = delete;
|
||||
public:
|
||||
static Manager& instance();
|
||||
uint8_t getCount();
|
||||
float getScale();
|
||||
void setScale(float scale);
|
||||
Instance* getCursor(uint8_t index = 0);
|
||||
uint16_t registerIcon(const QString& path);
|
||||
const QString& getIconImage(uint16_t icon);
|
||||
private:
|
||||
float _scale{ 1.0f };
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in a new issue