mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
merge new work into andrew/inertia
This commit is contained in:
commit
a7c4b02f2d
54 changed files with 942 additions and 887 deletions
|
@ -21,12 +21,10 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Systime.h"
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#else
|
#else
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#endif //_WIN32
|
#endif //_WIN32
|
||||||
|
|
||||||
|
@ -389,9 +387,8 @@ void AudioMixer::run() {
|
||||||
nodeList->linkedDataCreateCallback = attachNewBufferToNode;
|
nodeList->linkedDataCreateCallback = attachNewBufferToNode;
|
||||||
|
|
||||||
int nextFrame = 0;
|
int nextFrame = 0;
|
||||||
timeval startTime;
|
QElapsedTimer timer;
|
||||||
|
timer.start();
|
||||||
gettimeofday(&startTime, NULL);
|
|
||||||
|
|
||||||
char* clientMixBuffer = new char[NETWORK_BUFFER_LENGTH_BYTES_STEREO
|
char* clientMixBuffer = new char[NETWORK_BUFFER_LENGTH_BYTES_STEREO
|
||||||
+ numBytesForPacketHeaderGivenPacketType(PacketTypeMixedAudio)];
|
+ numBytesForPacketHeaderGivenPacketType(PacketTypeMixedAudio)];
|
||||||
|
@ -490,7 +487,7 @@ void AudioMixer::run() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow();
|
usecToSleep = (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - timer.nsecsElapsed() / 1000; // ns to us
|
||||||
|
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include "AssignmentClientMonitor.h"
|
#include "AssignmentClientMonitor.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
|
|
||||||
#include <Logging.h>
|
#include <Logging.h>
|
||||||
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include "DomainServer.h"
|
#include "DomainServer.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1088,7 +1088,6 @@ function keyPressEvent(event) {
|
||||||
red: colors[whichColor].red,
|
red: colors[whichColor].red,
|
||||||
green: colors[whichColor].green,
|
green: colors[whichColor].green,
|
||||||
blue: colors[whichColor].blue };
|
blue: colors[whichColor].blue };
|
||||||
Voxels.eraseVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s);
|
|
||||||
Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue);
|
Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue);
|
||||||
setAudioPosition();
|
setAudioPosition();
|
||||||
initialVoxelSound.playRandom();
|
initialVoxelSound.playRandom();
|
||||||
|
@ -1394,7 +1393,6 @@ function checkControllers() {
|
||||||
if (Vec3.length(Vec3.subtract(fingerTipPosition,lastFingerAddVoxel)) > (FINGERTIP_VOXEL_SIZE / 2)) {
|
if (Vec3.length(Vec3.subtract(fingerTipPosition,lastFingerAddVoxel)) > (FINGERTIP_VOXEL_SIZE / 2)) {
|
||||||
newColor = { red: colors[whichColor].red, green: colors[whichColor].green, blue: colors[whichColor].blue };
|
newColor = { red: colors[whichColor].red, green: colors[whichColor].green, blue: colors[whichColor].blue };
|
||||||
|
|
||||||
Voxels.eraseVoxel(fingerTipPosition.x, fingerTipPosition.y, fingerTipPosition.z, FINGERTIP_VOXEL_SIZE);
|
|
||||||
Voxels.setVoxel(fingerTipPosition.x, fingerTipPosition.y, fingerTipPosition.z, FINGERTIP_VOXEL_SIZE,
|
Voxels.setVoxel(fingerTipPosition.x, fingerTipPosition.y, fingerTipPosition.z, FINGERTIP_VOXEL_SIZE,
|
||||||
newColor.red, newColor.green, newColor.blue);
|
newColor.red, newColor.green, newColor.blue);
|
||||||
|
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="44px"
|
|
||||||
height="44px"
|
|
||||||
viewBox="0 0 44 44"
|
|
||||||
version="1.1"
|
|
||||||
id="svg2"
|
|
||||||
inkscape:version="0.48.3.1 r9886"
|
|
||||||
sodipodi:docname="close.svg">
|
|
||||||
<metadata
|
|
||||||
id="metadata16">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title>Slice 1</dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<sodipodi:namedview
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="640"
|
|
||||||
inkscape:window-height="480"
|
|
||||||
id="namedview14"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="3.7926636"
|
|
||||||
inkscape:cx="57.156875"
|
|
||||||
inkscape:cy="33.978935"
|
|
||||||
inkscape:window-x="536"
|
|
||||||
inkscape:window-y="258"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="svg2" />
|
|
||||||
<title
|
|
||||||
id="title4">Slice 1</title>
|
|
||||||
<description
|
|
||||||
id="description6">Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
|
|
||||||
<defs
|
|
||||||
id="defs8" />
|
|
||||||
<g
|
|
||||||
id="Page-1"
|
|
||||||
sketch:type="MSPage"
|
|
||||||
transform="translate(0.52733383,0.52733392)"
|
|
||||||
style="fill:none;stroke:none" />
|
|
||||||
<rect
|
|
||||||
id="rect2993"
|
|
||||||
width="5.7796612"
|
|
||||||
height="26.101694"
|
|
||||||
x="19.730724"
|
|
||||||
y="16.374792"
|
|
||||||
ry="3.371469" />
|
|
||||||
<rect
|
|
||||||
id="rect2995"
|
|
||||||
width="35.423729"
|
|
||||||
height="2.9830508"
|
|
||||||
x="4.6290293"
|
|
||||||
y="2.3917408"
|
|
||||||
ry="1.4915254" />
|
|
||||||
<rect
|
|
||||||
id="rect2999"
|
|
||||||
width="31.135593"
|
|
||||||
height="21.067797"
|
|
||||||
x="6.6798768"
|
|
||||||
y="4.0697069"
|
|
||||||
ry="1.4915254" />
|
|
||||||
<rect
|
|
||||||
style="fill:#ff0000"
|
|
||||||
id="rect3003"
|
|
||||||
width="27.779657"
|
|
||||||
height="17.711861"
|
|
||||||
x="8.171401"
|
|
||||||
y="5.3747911"
|
|
||||||
ry="0.46610171" />
|
|
||||||
<rect
|
|
||||||
style="fill:#999999"
|
|
||||||
id="rect3011"
|
|
||||||
width="3.1694915"
|
|
||||||
height="13.983051"
|
|
||||||
x="21.035809"
|
|
||||||
y="25.883266"
|
|
||||||
ry="0.46610171" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.5 KiB |
|
@ -1,106 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="44px"
|
|
||||||
height="44px"
|
|
||||||
viewBox="0 0 44 44"
|
|
||||||
version="1.1"
|
|
||||||
id="svg2"
|
|
||||||
inkscape:version="0.48.3.1 r9886"
|
|
||||||
sodipodi:docname="pin.svg">
|
|
||||||
<metadata
|
|
||||||
id="metadata16">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title>Slice 1</dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<sodipodi:namedview
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1920"
|
|
||||||
inkscape:window-height="1058"
|
|
||||||
id="namedview14"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="3.7926636"
|
|
||||||
inkscape:cx="39.754857"
|
|
||||||
inkscape:cy="33.978935"
|
|
||||||
inkscape:window-x="-8"
|
|
||||||
inkscape:window-y="-8"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg2" />
|
|
||||||
<title
|
|
||||||
id="title4">Slice 1</title>
|
|
||||||
<description
|
|
||||||
id="description6">Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
|
|
||||||
<defs
|
|
||||||
id="defs8" />
|
|
||||||
<g
|
|
||||||
id="Page-1"
|
|
||||||
sketch:type="MSPage"
|
|
||||||
transform="translate(0.52733383,0.52733392)"
|
|
||||||
style="fill:none;stroke:none" />
|
|
||||||
<rect
|
|
||||||
style="fill:#b3b3b3"
|
|
||||||
id="rect3013"
|
|
||||||
width="43.768692"
|
|
||||||
height="44.296078"
|
|
||||||
x="0.26366693"
|
|
||||||
y="-0.032378189"
|
|
||||||
ry="0.46610171" />
|
|
||||||
<rect
|
|
||||||
id="rect2993"
|
|
||||||
width="5.7796612"
|
|
||||||
height="26.101694"
|
|
||||||
x="19.730724"
|
|
||||||
y="16.374792"
|
|
||||||
ry="3.371469" />
|
|
||||||
<rect
|
|
||||||
id="rect2995"
|
|
||||||
width="35.423729"
|
|
||||||
height="2.9830508"
|
|
||||||
x="4.6290293"
|
|
||||||
y="2.3917408"
|
|
||||||
ry="1.4915254" />
|
|
||||||
<rect
|
|
||||||
id="rect2999"
|
|
||||||
width="31.135593"
|
|
||||||
height="21.067797"
|
|
||||||
x="6.6798768"
|
|
||||||
y="4.0697069"
|
|
||||||
ry="1.4915254" />
|
|
||||||
<rect
|
|
||||||
style="fill:#ff0000"
|
|
||||||
id="rect3003"
|
|
||||||
width="27.779657"
|
|
||||||
height="17.711861"
|
|
||||||
x="8.171401"
|
|
||||||
y="5.3747911"
|
|
||||||
ry="0.46610171" />
|
|
||||||
<rect
|
|
||||||
style="fill:#999999"
|
|
||||||
id="rect3011"
|
|
||||||
width="3.1694915"
|
|
||||||
height="13.983051"
|
|
||||||
x="21.035809"
|
|
||||||
y="25.883266"
|
|
||||||
ry="0.46610171" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.7 KiB |
|
@ -9,10 +9,6 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <Systime.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -134,7 +130,7 @@ QString& Application::resourcesPath() {
|
||||||
return staticResourcePath;
|
return staticResourcePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::Application(int& argc, char** argv, timeval &startup_time) :
|
Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
QApplication(argc, argv),
|
QApplication(argc, argv),
|
||||||
_window(new QMainWindow(desktop())),
|
_window(new QMainWindow(desktop())),
|
||||||
_glWidget(new GLCanvas()),
|
_glWidget(new GLCanvas()),
|
||||||
|
@ -507,7 +503,7 @@ void Application::initializeGL() {
|
||||||
_idleLoopStdev.reset();
|
_idleLoopStdev.reset();
|
||||||
|
|
||||||
if (_justStarted) {
|
if (_justStarted) {
|
||||||
float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime)) / 1000000.0;
|
float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0;
|
||||||
_justStarted = false;
|
_justStarted = false;
|
||||||
qDebug("Startup time: %4.2f seconds.", startupTime);
|
qDebug("Startup time: %4.2f seconds.", startupTime);
|
||||||
const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
|
const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
|
||||||
|
@ -1222,7 +1218,6 @@ void Application::touchEndEvent(QTouchEvent* event) {
|
||||||
if (_controllerScriptingInterface.isTouchCaptured()) {
|
if (_controllerScriptingInterface.isTouchCaptured()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// put any application specific touch behavior below here..
|
// put any application specific touch behavior below here..
|
||||||
_touchDragStartedAvgX = _touchAvgX;
|
_touchDragStartedAvgX = _touchAvgX;
|
||||||
_touchDragStartedAvgY = _touchAvgY;
|
_touchDragStartedAvgY = _touchAvgY;
|
||||||
|
@ -1276,21 +1271,21 @@ void Application::sendPingPackets() {
|
||||||
|
|
||||||
// Every second, check the frame rates and other stuff
|
// Every second, check the frame rates and other stuff
|
||||||
void Application::timer() {
|
void Application::timer() {
|
||||||
gettimeofday(&_timerEnd, NULL);
|
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
|
||||||
sendPingPackets();
|
sendPingPackets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0f;
|
||||||
|
|
||||||
_fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
|
_fps = (float)_frameCount / diffTime;
|
||||||
|
|
||||||
_packetsPerSecond = (float) _datagramProcessor.getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
|
_packetsPerSecond = (float) _datagramProcessor.getPacketCount() / diffTime;
|
||||||
_bytesPerSecond = (float) _datagramProcessor.getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
|
_bytesPerSecond = (float) _datagramProcessor.getByteCount() / diffTime;
|
||||||
_frameCount = 0;
|
_frameCount = 0;
|
||||||
|
|
||||||
_datagramProcessor.resetCounters();
|
_datagramProcessor.resetCounters();
|
||||||
|
|
||||||
gettimeofday(&_timerStart, NULL);
|
_timerStart.start();
|
||||||
|
|
||||||
// ask the node list to check in with the domain server
|
// ask the node list to check in with the domain server
|
||||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||||
|
@ -1303,13 +1298,11 @@ void Application::idle() {
|
||||||
bool showWarnings = getLogger()->extraDebugging();
|
bool showWarnings = getLogger()->extraDebugging();
|
||||||
PerformanceWarning warn(showWarnings, "Application::idle()");
|
PerformanceWarning warn(showWarnings, "Application::idle()");
|
||||||
|
|
||||||
timeval check;
|
|
||||||
gettimeofday(&check, NULL);
|
|
||||||
|
|
||||||
// Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran
|
// Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran
|
||||||
|
|
||||||
double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check);
|
double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0;
|
||||||
if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) {
|
if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) {
|
||||||
|
_lastTimeUpdated.start();
|
||||||
{
|
{
|
||||||
PerformanceWarning warn(showWarnings, "Application::idle()... update()");
|
PerformanceWarning warn(showWarnings, "Application::idle()... update()");
|
||||||
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
||||||
|
@ -1321,7 +1314,6 @@ void Application::idle() {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PerformanceWarning warn(showWarnings, "Application::idle()... rest of it");
|
PerformanceWarning warn(showWarnings, "Application::idle()... rest of it");
|
||||||
_lastTimeUpdated = check;
|
|
||||||
_idleLoopStdev.addValue(timeSinceLastUpdate);
|
_idleLoopStdev.addValue(timeSinceLastUpdate);
|
||||||
|
|
||||||
// Record standard deviation and reset counter if needed
|
// Record standard deviation and reset counter if needed
|
||||||
|
@ -1637,8 +1629,8 @@ void Application::init() {
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
gettimeofday(&_timerStart, NULL);
|
_timerStart.start();
|
||||||
gettimeofday(&_lastTimeUpdated, NULL);
|
_lastTimeUpdated.start();
|
||||||
|
|
||||||
Menu::getInstance()->loadSettings();
|
Menu::getInstance()->loadSettings();
|
||||||
if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) {
|
if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) {
|
||||||
|
@ -3528,35 +3520,30 @@ void Application::parseVersionXml() {
|
||||||
QString operatingSystem("ubuntu");
|
QString operatingSystem("ubuntu");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString releaseDate;
|
|
||||||
QString releaseNotes;
|
|
||||||
QString latestVersion;
|
QString latestVersion;
|
||||||
QUrl downloadUrl;
|
QUrl downloadUrl;
|
||||||
|
QString releaseNotes("Unavailable");
|
||||||
QObject* sender = QObject::sender();
|
QObject* sender = QObject::sender();
|
||||||
|
|
||||||
QXmlStreamReader xml(qobject_cast<QNetworkReply*>(sender));
|
QXmlStreamReader xml(qobject_cast<QNetworkReply*>(sender));
|
||||||
|
|
||||||
while (!xml.atEnd() && !xml.hasError()) {
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
QXmlStreamReader::TokenType token = xml.readNext();
|
if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == operatingSystem) {
|
||||||
|
while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == operatingSystem)) {
|
||||||
if (token == QXmlStreamReader::StartElement) {
|
if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "version") {
|
||||||
if (xml.name() == "ReleaseDate") {
|
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();
|
||||||
releaseDate = xml.text().toString();
|
|
||||||
}
|
|
||||||
if (xml.name() == "ReleaseNotes") {
|
|
||||||
xml.readNext();
|
|
||||||
releaseNotes = xml.text().toString();
|
|
||||||
}
|
|
||||||
if (xml.name() == "Version") {
|
|
||||||
xml.readNext();
|
|
||||||
latestVersion = xml.text().toString();
|
|
||||||
}
|
|
||||||
if (xml.name() == operatingSystem) {
|
|
||||||
xml.readNext();
|
|
||||||
downloadUrl = QUrl(xml.text().toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
xml.readNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldSkipVersion(latestVersion) && applicationVersion() != latestVersion) {
|
if (!shouldSkipVersion(latestVersion) && applicationVersion() != latestVersion) {
|
||||||
new UpdateDialog(_glWidget, releaseNotes, latestVersion, downloadUrl);
|
new UpdateDialog(_glWidget, releaseNotes, latestVersion, downloadUrl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QMainWindow>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
@ -117,7 +118,7 @@ public:
|
||||||
static Application* getInstance() { return static_cast<Application*>(QCoreApplication::instance()); }
|
static Application* getInstance() { return static_cast<Application*>(QCoreApplication::instance()); }
|
||||||
static QString& resourcesPath();
|
static QString& resourcesPath();
|
||||||
|
|
||||||
Application(int& argc, char** argv, timeval &startup_time);
|
Application(int& argc, char** argv, QElapsedTimer &startup_time);
|
||||||
~Application();
|
~Application();
|
||||||
|
|
||||||
void restoreSizeAndPosition();
|
void restoreSizeAndPosition();
|
||||||
|
@ -392,9 +393,9 @@ private:
|
||||||
|
|
||||||
int _frameCount;
|
int _frameCount;
|
||||||
float _fps;
|
float _fps;
|
||||||
timeval _applicationStartupTime;
|
QElapsedTimer _applicationStartupTime;
|
||||||
timeval _timerStart, _timerEnd;
|
QElapsedTimer _timerStart;
|
||||||
timeval _lastTimeUpdated;
|
QElapsedTimer _lastTimeUpdated;
|
||||||
bool _justStarted;
|
bool _justStarted;
|
||||||
Stars _stars;
|
Stars _stars;
|
||||||
|
|
||||||
|
|
|
@ -643,13 +643,12 @@ void Audio::handleAudioInput() {
|
||||||
void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
|
void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
|
||||||
const int NUM_INITIAL_PACKETS_DISCARD = 3;
|
const int NUM_INITIAL_PACKETS_DISCARD = 3;
|
||||||
const int STANDARD_DEVIATION_SAMPLE_COUNT = 500;
|
const int STANDARD_DEVIATION_SAMPLE_COUNT = 500;
|
||||||
|
|
||||||
timeval currentReceiveTime;
|
|
||||||
gettimeofday(¤tReceiveTime, NULL);
|
|
||||||
_totalPacketsReceived++;
|
_totalPacketsReceived++;
|
||||||
|
|
||||||
double timeDiff = diffclock(&_lastReceiveTime, ¤tReceiveTime);
|
double timeDiff = (double)_timeSinceLastReceived.nsecsElapsed() / 1000000.0; // ns to ms
|
||||||
|
_timeSinceLastReceived.start();
|
||||||
|
|
||||||
// Discard first few received packets for computing jitter (often they pile up on start)
|
// Discard first few received packets for computing jitter (often they pile up on start)
|
||||||
if (_totalPacketsReceived > NUM_INITIAL_PACKETS_DISCARD) {
|
if (_totalPacketsReceived > NUM_INITIAL_PACKETS_DISCARD) {
|
||||||
_stdev.addValue(timeDiff);
|
_stdev.addValue(timeDiff);
|
||||||
|
@ -673,8 +672,6 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO).updateValue(audioByteArray.size());
|
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO).updateValue(audioByteArray.size());
|
||||||
|
|
||||||
_lastReceiveTime = currentReceiveTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: numSamples is the total number of single channel samples, since callers will always call this with stereo
|
// NOTE: numSamples is the total number of single channel samples, since callers will always call this with stereo
|
||||||
|
@ -1268,13 +1265,13 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo)
|
||||||
// setup a procedural audio output device
|
// setup a procedural audio output device
|
||||||
_proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
_proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
||||||
|
|
||||||
gettimeofday(&_lastReceiveTime, NULL);
|
_timeSinceLastReceived.start();
|
||||||
|
|
||||||
// setup spatial audio ringbuffer
|
// setup spatial audio ringbuffer
|
||||||
int numFrameSamples = _outputFormat.sampleRate() * _desiredOutputFormat.channelCount();
|
int numFrameSamples = _outputFormat.sampleRate() * _desiredOutputFormat.channelCount();
|
||||||
_spatialAudioRingBuffer.resizeForFrameSize(numFrameSamples);
|
_spatialAudioRingBuffer.resizeForFrameSize(numFrameSamples);
|
||||||
_spatialAudioStart = _spatialAudioFinish = 0;
|
_spatialAudioStart = _spatialAudioFinish = 0;
|
||||||
|
|
||||||
supportedFormat = true;
|
supportedFormat = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,6 @@
|
||||||
#ifndef hifi_Audio_h
|
#ifndef hifi_Audio_h
|
||||||
#define hifi_Audio_h
|
#define hifi_Audio_h
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <Systime.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -23,6 +19,7 @@
|
||||||
|
|
||||||
#include <QAudio>
|
#include <QAudio>
|
||||||
#include <QAudioInput>
|
#include <QAudioInput>
|
||||||
|
#include <QElapsedTimer>
|
||||||
#include <QGLWidget>
|
#include <QGLWidget>
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtCore/QVector>
|
#include <QtCore/QVector>
|
||||||
|
@ -132,7 +129,7 @@ private:
|
||||||
QString _outputAudioDeviceName;
|
QString _outputAudioDeviceName;
|
||||||
|
|
||||||
StDev _stdev;
|
StDev _stdev;
|
||||||
timeval _lastReceiveTime;
|
QElapsedTimer _timeSinceLastReceived;
|
||||||
float _averagedLatency;
|
float _averagedLatency;
|
||||||
float _measuredJitter;
|
float _measuredJitter;
|
||||||
int16_t _jitterBufferSamples;
|
int16_t _jitterBufferSamples;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <QSlider>
|
#include <QSlider>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
#include <XmppClient.h>
|
#include <XmppClient.h>
|
||||||
|
@ -335,6 +336,8 @@ Menu::Menu() :
|
||||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false);
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false);
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false);
|
||||||
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false);
|
||||||
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true);
|
||||||
|
|
||||||
addDisabledActionAndSeparator(developerMenu, "Testing");
|
addDisabledActionAndSeparator(developerMenu, "Testing");
|
||||||
|
|
||||||
|
@ -968,6 +971,17 @@ void Menu::goToUser(const QString& user) {
|
||||||
connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision);
|
connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Open a url, shortcutting any "hifi" scheme URLs to the local application.
|
||||||
|
void Menu::openUrl(const QUrl& url) {
|
||||||
|
if (url.scheme() == "hifi") {
|
||||||
|
QString path = url.toString(QUrl::RemoveScheme);
|
||||||
|
path = path.remove(QRegExp("^:?/*"));
|
||||||
|
goTo(path);
|
||||||
|
} else {
|
||||||
|
QDesktopServices::openUrl(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) {
|
void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) {
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
msgBox.setText("Both user and location exists with same name");
|
msgBox.setText("Both user and location exists with same name");
|
||||||
|
@ -1143,23 +1157,22 @@ void Menu::showScriptEditor() {
|
||||||
void Menu::showChat() {
|
void Menu::showChat() {
|
||||||
QMainWindow* mainWindow = Application::getInstance()->getWindow();
|
QMainWindow* mainWindow = Application::getInstance()->getWindow();
|
||||||
if (!_chatWindow) {
|
if (!_chatWindow) {
|
||||||
mainWindow->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow());
|
_chatWindow = new ChatWindow(mainWindow);
|
||||||
}
|
}
|
||||||
if (!_chatWindow->toggleViewAction()->isChecked()) {
|
if (_chatWindow->isHidden()) {
|
||||||
const QRect& windowGeometry = mainWindow->geometry();
|
_chatWindow->show();
|
||||||
_chatWindow->move(windowGeometry.topRight().x() - _chatWindow->width(),
|
|
||||||
windowGeometry.topRight().y() + (windowGeometry.height() / 2) - (_chatWindow->height() / 2));
|
|
||||||
|
|
||||||
_chatWindow->resize(0, _chatWindow->height());
|
|
||||||
_chatWindow->toggleViewAction()->trigger();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::toggleChat() {
|
void Menu::toggleChat() {
|
||||||
#ifdef HAVE_QXMPP
|
#ifdef HAVE_QXMPP
|
||||||
_chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected());
|
_chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected());
|
||||||
if (!_chatAction->isEnabled() && _chatWindow && _chatWindow->toggleViewAction()->isChecked()) {
|
if (!_chatAction->isEnabled() && _chatWindow) {
|
||||||
_chatWindow->toggleViewAction()->trigger();
|
if (_chatWindow->isHidden()) {
|
||||||
|
_chatWindow->show();
|
||||||
|
} else {
|
||||||
|
_chatWindow->hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,7 @@ public slots:
|
||||||
void goTo();
|
void goTo();
|
||||||
void goToUser(const QString& user);
|
void goToUser(const QString& user);
|
||||||
void pasteToVoxel();
|
void pasteToVoxel();
|
||||||
|
void openUrl(const QUrl& url);
|
||||||
|
|
||||||
void toggleLoginMenuItem();
|
void toggleLoginMenuItem();
|
||||||
|
|
||||||
|
@ -256,6 +257,7 @@ private:
|
||||||
|
|
||||||
namespace MenuOption {
|
namespace MenuOption {
|
||||||
const QString AboutApp = "About Interface";
|
const QString AboutApp = "About Interface";
|
||||||
|
const QString AlignForearmsWithWrists = "Align Forearms with Wrists";
|
||||||
const QString AmbientOcclusion = "Ambient Occlusion";
|
const QString AmbientOcclusion = "Ambient Occlusion";
|
||||||
const QString Atmosphere = "Atmosphere";
|
const QString Atmosphere = "Atmosphere";
|
||||||
const QString AudioNoiseReduction = "Audio Noise Reduction";
|
const QString AudioNoiseReduction = "Audio Noise Reduction";
|
||||||
|
@ -354,6 +356,7 @@ namespace MenuOption {
|
||||||
const QString SettingsImport = "Import Settings";
|
const QString SettingsImport = "Import Settings";
|
||||||
const QString Shadows = "Shadows";
|
const QString Shadows = "Shadows";
|
||||||
const QString ShowCulledSharedFaces = "Show Culled Shared Voxel Faces";
|
const QString ShowCulledSharedFaces = "Show Culled Shared Voxel Faces";
|
||||||
|
const QString ShowIKConstraints = "Show IK Constraints";
|
||||||
const QString Stars = "Stars";
|
const QString Stars = "Stars";
|
||||||
const QString Stats = "Stats";
|
const QString Stats = "Stats";
|
||||||
const QString StopAllScripts = "Stop All Scripts";
|
const QString StopAllScripts = "Stop All Scripts";
|
||||||
|
|
|
@ -172,14 +172,6 @@ void renderWorldBox() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double diffclock(timeval *clock1,timeval *clock2)
|
|
||||||
{
|
|
||||||
double diffms = (clock2->tv_sec - clock1->tv_sec) * 1000.0;
|
|
||||||
diffms += (clock2->tv_usec - clock1->tv_usec) / 1000.0; // us to ms
|
|
||||||
|
|
||||||
return diffms;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a random vector of average length 1
|
// Return a random vector of average length 1
|
||||||
const glm::vec3 randVector() {
|
const glm::vec3 randVector() {
|
||||||
return glm::vec3(randFloat() - 0.5f, randFloat() - 0.5f, randFloat() - 0.5f) * 2.f;
|
return glm::vec3(randFloat() - 0.5f, randFloat() - 0.5f, randFloat() - 0.5f) * 2.f;
|
||||||
|
@ -411,69 +403,63 @@ void runTimingTests() {
|
||||||
int iResults[numTests];
|
int iResults[numTests];
|
||||||
float fTest = 1.0;
|
float fTest = 1.0;
|
||||||
float fResults[numTests];
|
float fResults[numTests];
|
||||||
timeval startTime, endTime;
|
QElapsedTimer startTime;
|
||||||
float elapsedMsecs;
|
startTime.start();
|
||||||
gettimeofday(&startTime, NULL);
|
float elapsedUsecs;
|
||||||
for (int i = 1; i < numTests; i++) {
|
|
||||||
gettimeofday(&endTime, NULL);
|
float NSEC_TO_USEC = 1.0f / 1000.0f;
|
||||||
}
|
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
|
||||||
elapsedMsecs = diffclock(&startTime, &endTime);
|
qDebug("QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs / (float) numTests);
|
||||||
qDebug("gettimeofday() usecs: %f", 1000.0f * elapsedMsecs / (float) numTests);
|
|
||||||
|
|
||||||
// Random number generation
|
// Random number generation
|
||||||
gettimeofday(&startTime, NULL);
|
startTime.start();
|
||||||
for (int i = 1; i < numTests; i++) {
|
for (int i = 1; i < numTests; i++) {
|
||||||
iResults[i] = rand();
|
iResults[i] = rand();
|
||||||
}
|
}
|
||||||
gettimeofday(&endTime, NULL);
|
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
|
||||||
elapsedMsecs = diffclock(&startTime, &endTime);
|
qDebug("rand() stored in array usecs: %f, first result:%d", elapsedUsecs / (float) numTests, iResults[0]);
|
||||||
qDebug("rand() stored in array usecs: %f, first result:%d", 1000.0f * elapsedMsecs / (float) numTests, iResults[0]);
|
|
||||||
|
|
||||||
// Random number generation using randFloat()
|
// Random number generation using randFloat()
|
||||||
gettimeofday(&startTime, NULL);
|
startTime.start();
|
||||||
for (int i = 1; i < numTests; i++) {
|
for (int i = 1; i < numTests; i++) {
|
||||||
fResults[i] = randFloat();
|
fResults[i] = randFloat();
|
||||||
}
|
}
|
||||||
gettimeofday(&endTime, NULL);
|
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
|
||||||
elapsedMsecs = diffclock(&startTime, &endTime);
|
qDebug("randFloat() stored in array usecs: %f, first result: %f", elapsedUsecs / (float) numTests, fResults[0]);
|
||||||
qDebug("randFloat() stored in array usecs: %f, first result: %f", 1000.0f * elapsedMsecs / (float) numTests, fResults[0]);
|
|
||||||
|
|
||||||
// PowF function
|
// PowF function
|
||||||
fTest = 1145323.2342f;
|
fTest = 1145323.2342f;
|
||||||
gettimeofday(&startTime, NULL);
|
startTime.start();
|
||||||
for (int i = 1; i < numTests; i++) {
|
for (int i = 1; i < numTests; i++) {
|
||||||
fTest = powf(fTest, 0.5f);
|
fTest = powf(fTest, 0.5f);
|
||||||
}
|
}
|
||||||
gettimeofday(&endTime, NULL);
|
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
|
||||||
elapsedMsecs = diffclock(&startTime, &endTime);
|
qDebug("powf(f, 0.5) usecs: %f", elapsedUsecs / (float) numTests);
|
||||||
qDebug("powf(f, 0.5) usecs: %f", 1000.0f * elapsedMsecs / (float) numTests);
|
|
||||||
|
|
||||||
// Vector Math
|
// Vector Math
|
||||||
float distance;
|
float distance;
|
||||||
glm::vec3 pointA(randVector()), pointB(randVector());
|
glm::vec3 pointA(randVector()), pointB(randVector());
|
||||||
gettimeofday(&startTime, NULL);
|
startTime.start();
|
||||||
for (int i = 1; i < numTests; i++) {
|
for (int i = 1; i < numTests; i++) {
|
||||||
//glm::vec3 temp = pointA - pointB;
|
//glm::vec3 temp = pointA - pointB;
|
||||||
//float distanceSquared = glm::dot(temp, temp);
|
//float distanceSquared = glm::dot(temp, temp);
|
||||||
distance = glm::distance(pointA, pointB);
|
distance = glm::distance(pointA, pointB);
|
||||||
}
|
}
|
||||||
gettimeofday(&endTime, NULL);
|
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
|
||||||
elapsedMsecs = diffclock(&startTime, &endTime);
|
qDebug("vector math usecs: %f [%f usecs total for %d tests], last result:%f",
|
||||||
qDebug("vector math usecs: %f [%f msecs total for %d tests], last result:%f",
|
elapsedUsecs / (float) numTests, elapsedUsecs, numTests, distance);
|
||||||
1000.0f * elapsedMsecs / (float) numTests, elapsedMsecs, numTests, distance);
|
|
||||||
|
|
||||||
// Vec3 test
|
// Vec3 test
|
||||||
glm::vec3 vecA(randVector()), vecB(randVector());
|
glm::vec3 vecA(randVector()), vecB(randVector());
|
||||||
float result;
|
float result;
|
||||||
|
|
||||||
gettimeofday(&startTime, NULL);
|
startTime.start();
|
||||||
for (int i = 1; i < numTests; i++) {
|
for (int i = 1; i < numTests; i++) {
|
||||||
glm::vec3 temp = vecA-vecB;
|
glm::vec3 temp = vecA-vecB;
|
||||||
result = glm::dot(temp,temp);
|
result = glm::dot(temp,temp);
|
||||||
}
|
}
|
||||||
gettimeofday(&endTime, NULL);
|
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
|
||||||
elapsedMsecs = diffclock(&startTime, &endTime);
|
qDebug("vec3 assign and dot() usecs: %f, last result:%f", elapsedUsecs / (float) numTests, result);
|
||||||
qDebug("vec3 assign and dot() usecs: %f, last result:%f", 1000.0f * elapsedMsecs / (float) numTests, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float loadSetting(QSettings* settings, const char* name, float defaultValue) {
|
float loadSetting(QSettings* settings, const char* name, float defaultValue) {
|
||||||
|
|
|
@ -12,12 +12,6 @@
|
||||||
#ifndef hifi_Util_h
|
#ifndef hifi_Util_h
|
||||||
#define hifi_Util_h
|
#define hifi_Util_h
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include "Systime.h"
|
|
||||||
#else
|
|
||||||
#include <sys/time.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
@ -44,8 +38,6 @@ void drawVector(glm::vec3* vector);
|
||||||
|
|
||||||
void printVector(glm::vec3 vec);
|
void printVector(glm::vec3 vec);
|
||||||
|
|
||||||
double diffclock(timeval *clock1,timeval *clock2);
|
|
||||||
|
|
||||||
void renderCollisionOverlay(int width, int height, float magnitude, float red = 0, float blue = 0, float green = 0);
|
void renderCollisionOverlay(int width, int height, float magnitude, float red = 0, float blue = 0, float green = 0);
|
||||||
|
|
||||||
void renderOrientationDirections( glm::vec3 position, const glm::quat& orientation, float size );
|
void renderOrientationDirections( glm::vec3 position, const glm::quat& orientation, float size );
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
|
|
||||||
#include <glm/gtx/norm.hpp>
|
#include <glm/gtx/norm.hpp>
|
||||||
|
@ -413,8 +414,13 @@ void MyAvatar::renderDebugBodyPoints() {
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
||||||
if (_shouldRender) {
|
// don't render if we've been asked to disable local rendering
|
||||||
Avatar::render(cameraPosition, renderMode);
|
if (!_shouldRender) {
|
||||||
|
return; // exit early
|
||||||
|
}
|
||||||
|
Avatar::render(cameraPosition, renderMode);
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints)) {
|
||||||
|
_skeletonModel.renderIKConstraints();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1134,6 +1140,8 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
|
||||||
coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER;
|
coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER;
|
||||||
setPosition(newPosition);
|
setPosition(newPosition);
|
||||||
emit transformChanged();
|
emit transformChanged();
|
||||||
|
} else {
|
||||||
|
QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,11 @@ void SkeletonModel::getBodyShapes(QVector<const Shape*>& shapes) const {
|
||||||
shapes.push_back(&_boundingShape);
|
shapes.push_back(&_boundingShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonModel::renderIKConstraints() {
|
||||||
|
renderJointConstraints(getRightHandJointIndex());
|
||||||
|
renderJointConstraints(getLeftHandJointIndex());
|
||||||
|
}
|
||||||
|
|
||||||
class IndexValue {
|
class IndexValue {
|
||||||
public:
|
public:
|
||||||
int index;
|
int index;
|
||||||
|
@ -133,7 +138,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position)
|
||||||
|
|
||||||
// align hand with forearm
|
// align hand with forearm
|
||||||
float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f;
|
float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f;
|
||||||
applyRotationDelta(jointIndex, rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), false);
|
applyRotationDelta(jointIndex, rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJointIndices,
|
void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJointIndices,
|
||||||
|
@ -148,12 +153,15 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rotate forearm to align with palm direction
|
// rotate palm to align with palm direction
|
||||||
glm::quat palmRotation;
|
glm::quat palmRotation;
|
||||||
getJointRotation(parentJointIndex, palmRotation, true);
|
if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) {
|
||||||
applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()), false);
|
getJointRotation(parentJointIndex, palmRotation, true);
|
||||||
getJointRotation(parentJointIndex, palmRotation, true);
|
} else {
|
||||||
|
getJointRotation(jointIndex, palmRotation, true);
|
||||||
|
}
|
||||||
|
palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation;
|
||||||
|
|
||||||
// sort the finger indices by raw x, get the average direction
|
// sort the finger indices by raw x, get the average direction
|
||||||
QVector<IndexValue> fingerIndices;
|
QVector<IndexValue> fingerIndices;
|
||||||
glm::vec3 direction;
|
glm::vec3 direction;
|
||||||
|
@ -173,17 +181,20 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
|
||||||
float directionLength = glm::length(direction);
|
float directionLength = glm::length(direction);
|
||||||
const unsigned int MIN_ROTATION_FINGERS = 3;
|
const unsigned int MIN_ROTATION_FINGERS = 3;
|
||||||
if (directionLength > EPSILON && palm.getNumFingers() >= MIN_ROTATION_FINGERS) {
|
if (directionLength > EPSILON && palm.getNumFingers() >= MIN_ROTATION_FINGERS) {
|
||||||
applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction), false);
|
palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation;
|
||||||
getJointRotation(parentJointIndex, palmRotation, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// let wrist inherit forearm rotation
|
// set hand position, rotation
|
||||||
_jointStates[jointIndex].rotation = glm::quat();
|
if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) {
|
||||||
|
glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f);
|
||||||
// set elbow position from wrist position
|
setJointPosition(parentJointIndex, palm.getPosition() + forearmVector *
|
||||||
glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f);
|
geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale));
|
||||||
setJointPosition(parentJointIndex, palm.getPosition() + forearmVector *
|
setJointRotation(parentJointIndex, palmRotation, true);
|
||||||
geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale));
|
_jointStates[jointIndex].rotation = glm::quat();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
setJointPosition(jointIndex, palm.getPosition(), palmRotation, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonModel::updateJointState(int index) {
|
void SkeletonModel::updateJointState(int index) {
|
||||||
|
@ -210,3 +221,59 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const
|
||||||
glm::normalize(inverse * axes[0])) * joint.rotation;
|
glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonModel::renderJointConstraints(int jointIndex) {
|
||||||
|
if (jointIndex == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
const float BASE_DIRECTION_SIZE = 300.0f;
|
||||||
|
float directionSize = BASE_DIRECTION_SIZE * extractUniformScale(_scale);
|
||||||
|
glLineWidth(3.0f);
|
||||||
|
do {
|
||||||
|
const FBXJoint& joint = geometry.joints.at(jointIndex);
|
||||||
|
const JointState& jointState = _jointStates.at(jointIndex);
|
||||||
|
glm::vec3 position = extractTranslation(jointState.transform) + _translation;
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(position.x, position.y, position.z);
|
||||||
|
glm::quat parentRotation = (joint.parentIndex == -1) ? _rotation : _jointStates.at(joint.parentIndex).combinedRotation;
|
||||||
|
glm::vec3 rotationAxis = glm::axis(parentRotation);
|
||||||
|
glRotatef(glm::degrees(glm::angle(parentRotation)), rotationAxis.x, rotationAxis.y, rotationAxis.z);
|
||||||
|
float fanScale = directionSize * 0.75f;
|
||||||
|
glScalef(fanScale, fanScale, fanScale);
|
||||||
|
const int AXIS_COUNT = 3;
|
||||||
|
for (int i = 0; i < AXIS_COUNT; i++) {
|
||||||
|
if (joint.rotationMin[i] <= -PI + EPSILON && joint.rotationMax[i] >= PI - EPSILON) {
|
||||||
|
continue; // unconstrained
|
||||||
|
}
|
||||||
|
glm::vec3 axis;
|
||||||
|
axis[i] = 1.0f;
|
||||||
|
|
||||||
|
glm::vec3 otherAxis;
|
||||||
|
if (i == 0) {
|
||||||
|
otherAxis.y = 1.0f;
|
||||||
|
} else {
|
||||||
|
otherAxis.x = 1.0f;
|
||||||
|
}
|
||||||
|
glColor4f(otherAxis.r, otherAxis.g, otherAxis.b, 0.75f);
|
||||||
|
|
||||||
|
glBegin(GL_TRIANGLE_FAN);
|
||||||
|
glVertex3f(0.0f, 0.0f, 0.0f);
|
||||||
|
const int FAN_SEGMENTS = 16;
|
||||||
|
for (int j = 0; j < FAN_SEGMENTS; j++) {
|
||||||
|
glm::vec3 rotated = glm::angleAxis(glm::mix(joint.rotationMin[i], joint.rotationMax[i],
|
||||||
|
(float)j / (FAN_SEGMENTS - 1)), axis) * otherAxis;
|
||||||
|
glVertex3f(rotated.x, rotated.y, rotated.z);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
renderOrientationDirections(position, jointState.combinedRotation, directionSize);
|
||||||
|
jointIndex = joint.parentIndex;
|
||||||
|
|
||||||
|
} while (jointIndex != -1 && geometry.joints.at(jointIndex).isFree);
|
||||||
|
|
||||||
|
glLineWidth(1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ public:
|
||||||
/// \param shapes[out] list of shapes for body collisions
|
/// \param shapes[out] list of shapes for body collisions
|
||||||
void getBodyShapes(QVector<const Shape*>& shapes) const;
|
void getBodyShapes(QVector<const Shape*>& shapes) const;
|
||||||
|
|
||||||
|
void renderIKConstraints();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void applyHandPosition(int jointIndex, const glm::vec3& position);
|
void applyHandPosition(int jointIndex, const glm::vec3& position);
|
||||||
|
@ -46,6 +48,8 @@ protected:
|
||||||
virtual void maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state);
|
virtual void maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void renderJointConstraints(int jointIndex);
|
||||||
|
|
||||||
Avatar* _owningAvatar;
|
Avatar* _owningAvatar;
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,10 +11,6 @@
|
||||||
|
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <Systime.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QOpenGLFramebufferObject>
|
#include <QOpenGLFramebufferObject>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
|
@ -15,11 +15,6 @@
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <Systime.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
#include "TV3DManager.h"
|
#include "TV3DManager.h"
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "LocationManager.h"
|
#include "LocationManager.h"
|
||||||
|
|
||||||
|
@ -118,6 +120,8 @@ void LocationManager::checkForMultipleDestinations() {
|
||||||
Application::getInstance()->getAvatar()->goToLocationFromResponse(_placeData);
|
Application::getInstance()->getAvatar()->goToLocationFromResponse(_placeData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
int main(int argc, const char * argv[]) {
|
int main(int argc, const char * argv[]) {
|
||||||
timeval startup_time;
|
QElapsedTimer startupTime;
|
||||||
gettimeofday(&startup_time, NULL);
|
startupTime.start();
|
||||||
|
|
||||||
// Debug option to demonstrate that the client's local time does not
|
// Debug option to demonstrate that the client's local time does not
|
||||||
// need to be in sync with any other network node. This forces clock
|
// need to be in sync with any other network node. This forces clock
|
||||||
|
@ -33,7 +33,7 @@ int main(int argc, const char * argv[]) {
|
||||||
int exitCode;
|
int exitCode;
|
||||||
{
|
{
|
||||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||||
Application app(argc, const_cast<char**>(argv), startup_time);
|
Application app(argc, const_cast<char**>(argv), startupTime);
|
||||||
|
|
||||||
QTranslator translator;
|
QTranslator translator;
|
||||||
translator.load("interface_en");
|
translator.load("interface_en");
|
||||||
|
|
|
@ -882,12 +882,12 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex,
|
bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation, bool useRotation,
|
||||||
bool allIntermediatesFree, const glm::vec3& alignment) {
|
int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment) {
|
||||||
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
glm::vec3 relativePosition = position - _translation;
|
glm::vec3 relativePosition = translation - _translation;
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage;
|
const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage;
|
||||||
if (freeLineage.isEmpty()) {
|
if (freeLineage.isEmpty()) {
|
||||||
|
@ -896,13 +896,21 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last
|
||||||
if (lastFreeIndex == -1) {
|
if (lastFreeIndex == -1) {
|
||||||
lastFreeIndex = freeLineage.last();
|
lastFreeIndex = freeLineage.last();
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a cyclic coordinate descent algorithm: see
|
// this is a cyclic coordinate descent algorithm: see
|
||||||
// http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d
|
// http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d
|
||||||
const int ITERATION_COUNT = 1;
|
const int ITERATION_COUNT = 1;
|
||||||
glm::vec3 worldAlignment = _rotation * alignment;
|
glm::vec3 worldAlignment = _rotation * alignment;
|
||||||
for (int i = 0; i < ITERATION_COUNT; i++) {
|
for (int i = 0; i < ITERATION_COUNT; i++) {
|
||||||
// first, we go from the joint upwards, rotating the end as close as possible to the target
|
// first, try to rotate the end effector as close as possible to the target rotation, if any
|
||||||
|
glm::quat endRotation;
|
||||||
|
if (useRotation) {
|
||||||
|
getJointRotation(jointIndex, endRotation, true);
|
||||||
|
applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation));
|
||||||
|
getJointRotation(jointIndex, endRotation, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then, we go from the joint upwards, rotating the end as close as possible to the target
|
||||||
glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].transform);
|
glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].transform);
|
||||||
for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) {
|
for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) {
|
||||||
int index = freeLineage.at(j);
|
int index = freeLineage.at(j);
|
||||||
|
@ -914,8 +922,17 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last
|
||||||
glm::vec3 jointPosition = extractTranslation(state.transform);
|
glm::vec3 jointPosition = extractTranslation(state.transform);
|
||||||
glm::vec3 jointVector = endPosition - jointPosition;
|
glm::vec3 jointVector = endPosition - jointPosition;
|
||||||
glm::quat oldCombinedRotation = state.combinedRotation;
|
glm::quat oldCombinedRotation = state.combinedRotation;
|
||||||
applyRotationDelta(index, rotationBetween(jointVector, relativePosition - jointPosition));
|
glm::quat combinedDelta;
|
||||||
endPosition = state.combinedRotation * glm::inverse(oldCombinedRotation) * jointVector + jointPosition;
|
float combinedWeight;
|
||||||
|
if (useRotation) {
|
||||||
|
combinedDelta = safeMix(rotation * glm::inverse(endRotation),
|
||||||
|
rotationBetween(jointVector, relativePosition - jointPosition), 0.5f);
|
||||||
|
combinedWeight = 2.0f;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
combinedDelta = rotationBetween(jointVector, relativePosition - jointPosition);
|
||||||
|
combinedWeight = 1.0f;
|
||||||
|
}
|
||||||
if (alignment != glm::vec3() && j > 1) {
|
if (alignment != glm::vec3() && j > 1) {
|
||||||
jointVector = endPosition - jointPosition;
|
jointVector = endPosition - jointPosition;
|
||||||
glm::vec3 positionSum;
|
glm::vec3 positionSum;
|
||||||
|
@ -929,9 +946,16 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last
|
||||||
glm::vec3 projectedAlignment = glm::cross(jointVector, glm::cross(worldAlignment, jointVector));
|
glm::vec3 projectedAlignment = glm::cross(jointVector, glm::cross(worldAlignment, jointVector));
|
||||||
const float LENGTH_EPSILON = 0.001f;
|
const float LENGTH_EPSILON = 0.001f;
|
||||||
if (glm::length(projectedCenterOfMass) > LENGTH_EPSILON && glm::length(projectedAlignment) > LENGTH_EPSILON) {
|
if (glm::length(projectedCenterOfMass) > LENGTH_EPSILON && glm::length(projectedAlignment) > LENGTH_EPSILON) {
|
||||||
applyRotationDelta(index, rotationBetween(projectedCenterOfMass, projectedAlignment));
|
combinedDelta = safeMix(combinedDelta, rotationBetween(projectedCenterOfMass, projectedAlignment),
|
||||||
|
1.0f / (combinedWeight + 1.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
applyRotationDelta(index, combinedDelta);
|
||||||
|
glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation);
|
||||||
|
endPosition = actualDelta * jointVector + jointPosition;
|
||||||
|
if (useRotation) {
|
||||||
|
endRotation = actualDelta * endRotation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1012,8 +1036,9 @@ void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool cons
|
||||||
state.combinedRotation = delta * state.combinedRotation;
|
state.combinedRotation = delta * state.combinedRotation;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
glm::quat newRotation = glm::quat(glm::clamp(safeEulerAngles(state.rotation *
|
glm::quat targetRotation = delta * state.combinedRotation;
|
||||||
glm::inverse(state.combinedRotation) * delta * state.combinedRotation), joint.rotationMin, joint.rotationMax));
|
glm::vec3 eulers = safeEulerAngles(state.rotation * glm::inverse(state.combinedRotation) * targetRotation);
|
||||||
|
glm::quat newRotation = glm::quat(glm::clamp(eulers, joint.rotationMin, joint.rotationMax));
|
||||||
state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation;
|
state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation;
|
||||||
state.rotation = newRotation;
|
state.rotation = newRotation;
|
||||||
}
|
}
|
||||||
|
@ -1141,7 +1166,7 @@ void Model::applyCollision(CollisionInfo& collision) {
|
||||||
getJointPosition(jointIndex, end);
|
getJointPosition(jointIndex, end);
|
||||||
glm::vec3 newEnd = start + glm::angleAxis(angle, axis) * (end - start);
|
glm::vec3 newEnd = start + glm::angleAxis(angle, axis) * (end - start);
|
||||||
// try to move it
|
// try to move it
|
||||||
setJointPosition(jointIndex, newEnd, -1, true);
|
setJointPosition(jointIndex, newEnd, glm::quat(), false, -1, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,8 +242,9 @@ protected:
|
||||||
bool getJointPosition(int jointIndex, glm::vec3& position) const;
|
bool getJointPosition(int jointIndex, glm::vec3& position) const;
|
||||||
bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const;
|
bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const;
|
||||||
|
|
||||||
bool setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex = -1,
|
bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(),
|
||||||
bool allIntermediatesFree = false, const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f));
|
bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false,
|
||||||
|
const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f));
|
||||||
bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false);
|
bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false);
|
||||||
|
|
||||||
void setJointTranslation(int jointIndex, const glm::vec3& translation);
|
void setJointTranslation(int jointIndex, const glm::vec3& translation);
|
||||||
|
|
|
@ -9,24 +9,23 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifdef _WIN32
|
#include <QElapsedTimer>
|
||||||
#include <Systime.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "starfield/Controller.h"
|
#include "starfield/Controller.h"
|
||||||
|
|
||||||
using namespace starfield;
|
using namespace starfield;
|
||||||
|
|
||||||
bool Controller::computeStars(unsigned numStars, unsigned seed) {
|
bool Controller::computeStars(unsigned numStars, unsigned seed) {
|
||||||
timeval startTime;
|
QElapsedTimer startTime;
|
||||||
gettimeofday(&startTime, NULL);
|
startTime.start();
|
||||||
|
|
||||||
Generator::computeStarPositions(_inputSequence, numStars, seed);
|
Generator::computeStarPositions(_inputSequence, numStars, seed);
|
||||||
|
|
||||||
this->retile(numStars, _tileResolution);
|
this->retile(numStars, _tileResolution);
|
||||||
|
|
||||||
qDebug() << "Total time to retile and generate stars: "
|
double NSEC_TO_MSEC = 1.0 / 1000000.0;
|
||||||
<< ((usecTimestampNow() - usecTimestamp(&startTime)) / 1000) << "msec";
|
double timeDiff = (double)startTime.nsecsElapsed() * NSEC_TO_MSEC;
|
||||||
|
qDebug() << "Total time to retile and generate stars: " << timeDiff << "msec";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifdef _WIN32
|
#include <QElapsedTimer>
|
||||||
#include <Systime.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "starfield/Generator.h"
|
#include "starfield/Generator.h"
|
||||||
|
|
||||||
|
@ -24,8 +22,8 @@ void Generator::computeStarPositions(InputVertices& destination, unsigned limit,
|
||||||
InputVertices* vertices = & destination;
|
InputVertices* vertices = & destination;
|
||||||
//_limit = limit;
|
//_limit = limit;
|
||||||
|
|
||||||
timeval startTime;
|
QElapsedTimer startTime;
|
||||||
gettimeofday(&startTime, NULL);
|
startTime.start();
|
||||||
|
|
||||||
srand(seed);
|
srand(seed);
|
||||||
|
|
||||||
|
@ -70,7 +68,8 @@ void Generator::computeStarPositions(InputVertices& destination, unsigned limit,
|
||||||
vertices->push_back(InputVertex(azimuth, altitude, computeStarColor(STAR_COLORIZATION)));
|
vertices->push_back(InputVertex(azimuth, altitude, computeStarColor(STAR_COLORIZATION)));
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Total time to generate stars: " << ((usecTimestampNow() - usecTimestamp(&startTime)) / 1000) << " msec";
|
double timeDiff = (double)startTime.nsecsElapsed() / 1000000.0; // ns to ms
|
||||||
|
qDebug() << "Total time to generate stars: " << timeDiff << " msec";
|
||||||
}
|
}
|
||||||
|
|
||||||
// computeStarColor
|
// computeStarColor
|
||||||
|
|
|
@ -62,26 +62,21 @@ BandwidthMeter::~BandwidthMeter() {
|
||||||
free(_channels);
|
free(_channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
BandwidthMeter::Stream::Stream(float msToAverage) :
|
BandwidthMeter::Stream::Stream(float msToAverage) : _value(0.0f), _msToAverage(msToAverage) {
|
||||||
_value(0.0f),
|
_prevTime.start();
|
||||||
_msToAverage(msToAverage) {
|
|
||||||
|
|
||||||
gettimeofday(& _prevTime, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BandwidthMeter::Stream::updateValue(double amount) {
|
void BandwidthMeter::Stream::updateValue(double amount) {
|
||||||
|
|
||||||
// Determine elapsed time
|
// Determine elapsed time
|
||||||
timeval now;
|
double dt = (double)_prevTime.nsecsElapsed() / 1000000.0; // ns to ms
|
||||||
gettimeofday(& now, NULL);
|
|
||||||
double dt = diffclock(& _prevTime, & now);
|
|
||||||
|
|
||||||
// Ignore this value when timer imprecision yields dt = 0
|
// Ignore this value when timer imprecision yields dt = 0
|
||||||
if (dt == 0.0) {
|
if (dt == 0.0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(& _prevTime, & now, sizeof(timeval));
|
_prevTime.start();
|
||||||
|
|
||||||
// Compute approximate average
|
// Compute approximate average
|
||||||
_value = glm::mix(_value, amount / dt,
|
_value = glm::mix(_value, amount / dt,
|
||||||
|
|
|
@ -12,9 +12,7 @@
|
||||||
#ifndef hifi_BandwidthMeter_h
|
#ifndef hifi_BandwidthMeter_h
|
||||||
#define hifi_BandwidthMeter_h
|
#define hifi_BandwidthMeter_h
|
||||||
|
|
||||||
#ifdef _WIN32
|
#include <QElapsedTimer>
|
||||||
#include <Systime.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
@ -59,7 +57,7 @@ public:
|
||||||
private:
|
private:
|
||||||
double _value; // Current value.
|
double _value; // Current value.
|
||||||
double _msToAverage; // Milliseconds to average.
|
double _msToAverage; // Milliseconds to average.
|
||||||
timeval _prevTime; // Time of last feed.
|
QElapsedTimer _prevTime; // Time of last feed.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Data model accessors
|
// Data model accessors
|
||||||
|
|
19
interface/src/ui/ChatInputArea.cpp
Normal file
19
interface/src/ui/ChatInputArea.cpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//
|
||||||
|
// ChatInputArea.cpp
|
||||||
|
// interface/src/ui
|
||||||
|
//
|
||||||
|
// Created by Ryan Huffman on 4/24/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "ChatInputArea.h"
|
||||||
|
|
||||||
|
ChatInputArea::ChatInputArea(QWidget* parent) : QTextEdit(parent) {
|
||||||
|
};
|
||||||
|
|
||||||
|
void ChatInputArea::insertFromMimeData(const QMimeData* source) {
|
||||||
|
insertPlainText(source->text());
|
||||||
|
};
|
27
interface/src/ui/ChatInputArea.h
Normal file
27
interface/src/ui/ChatInputArea.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
//
|
||||||
|
// ChatInputArea.h
|
||||||
|
// interface/src/ui
|
||||||
|
//
|
||||||
|
// Created by Ryan Huffman on 4/11/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_ChatInputArea_h
|
||||||
|
#define hifi_ChatInputArea_h
|
||||||
|
|
||||||
|
#include <QTextBrowser>
|
||||||
|
#include <QMimeData>
|
||||||
|
|
||||||
|
class ChatInputArea : public QTextEdit {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ChatInputArea(QWidget* parent);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void insertFromMimeData(const QMimeData* source);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_ChatInputArea_h
|
|
@ -9,13 +9,18 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
#include "ChatMessageArea.h"
|
#include "ChatMessageArea.h"
|
||||||
#include <QAbstractTextDocumentLayout>
|
#include <QAbstractTextDocumentLayout>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
|
|
||||||
ChatMessageArea::ChatMessageArea() : QTextBrowser() {
|
ChatMessageArea::ChatMessageArea(bool useFixedHeight) : QTextBrowser(), _useFixedHeight(useFixedHeight) {
|
||||||
|
setOpenLinks(false);
|
||||||
|
|
||||||
connect(document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
|
connect(document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
|
||||||
this, &ChatMessageArea::updateLayout);
|
this, &ChatMessageArea::updateLayout);
|
||||||
|
connect(this, &QTextBrowser::anchorClicked,
|
||||||
|
Menu::getInstance(), &Menu::openUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatMessageArea::setHtml(const QString& html) {
|
void ChatMessageArea::setHtml(const QString& html) {
|
||||||
|
@ -34,7 +39,15 @@ void ChatMessageArea::setHtml(const QString& html) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatMessageArea::updateLayout() {
|
void ChatMessageArea::updateLayout() {
|
||||||
setFixedHeight(document()->size().height());
|
if (_useFixedHeight) {
|
||||||
|
setFixedHeight(document()->size().height());
|
||||||
|
updateGeometry();
|
||||||
|
emit sizeChanged(size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatMessageArea::setSize(const QSize& size) {
|
||||||
|
setFixedHeight(size.height());
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,15 +19,19 @@ const int CHAT_MESSAGE_LINE_HEIGHT = 130;
|
||||||
class ChatMessageArea : public QTextBrowser {
|
class ChatMessageArea : public QTextBrowser {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ChatMessageArea();
|
ChatMessageArea(bool useFixedHeight = true);
|
||||||
virtual void setHtml(const QString& html);
|
virtual void setHtml(const QString& html);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateLayout();
|
void updateLayout();
|
||||||
|
void setSize(const QSize& size);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sizeChanged(QSize newSize);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void wheelEvent(QWheelEvent* event);
|
virtual void wheelEvent(QWheelEvent* event);
|
||||||
|
bool _useFixedHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ChatMessageArea_h
|
#endif // hifi_ChatMessageArea_h
|
||||||
|
|
|
@ -12,12 +12,10 @@
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QLayoutItem>
|
#include <QLayoutItem>
|
||||||
#include <QMainWindow>
|
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QSizePolicy>
|
#include <QSizePolicy>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "FlowLayout.h"
|
#include "FlowLayout.h"
|
||||||
|
@ -31,32 +29,40 @@
|
||||||
const int NUM_MESSAGES_TO_TIME_STAMP = 20;
|
const int NUM_MESSAGES_TO_TIME_STAMP = 20;
|
||||||
|
|
||||||
const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)");
|
const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)");
|
||||||
|
const QRegularExpression regexHifiLinks("([#@]\\S+)");
|
||||||
|
|
||||||
ChatWindow::ChatWindow() :
|
ChatWindow::ChatWindow(QWidget* parent) :
|
||||||
|
FramelessDialog(parent, 0, POSITION_RIGHT),
|
||||||
ui(new Ui::ChatWindow),
|
ui(new Ui::ChatWindow),
|
||||||
numMessagesAfterLastTimeStamp(0),
|
numMessagesAfterLastTimeStamp(0),
|
||||||
_mousePressed(false),
|
_mousePressed(false),
|
||||||
_mouseStartPosition()
|
_mouseStartPosition()
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
setAttribute(Qt::WA_DeleteOnClose, false);
|
||||||
|
|
||||||
// remove the title bar (see the Qt docs on setTitleBarWidget), but we keep it for undocking
|
ui->setupUi(this);
|
||||||
//
|
|
||||||
titleBar = titleBarWidget();
|
|
||||||
setTitleBarWidget(new QWidget());
|
|
||||||
|
|
||||||
FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
|
FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
|
||||||
ui->usersWidget->setLayout(flowLayout);
|
ui->usersWidget->setLayout(flowLayout);
|
||||||
|
|
||||||
ui->messagesGridLayout->setColumnStretch(0, 1);
|
|
||||||
ui->messagesGridLayout->setColumnStretch(1, 3);
|
|
||||||
|
|
||||||
ui->messagePlainTextEdit->installEventFilter(this);
|
ui->messagePlainTextEdit->installEventFilter(this);
|
||||||
|
ui->messagePlainTextEdit->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
|
||||||
|
|
||||||
|
QTextCursor cursor(ui->messagePlainTextEdit->textCursor());
|
||||||
|
|
||||||
|
cursor.movePosition(QTextCursor::Start);
|
||||||
|
|
||||||
|
QTextBlockFormat format = cursor.blockFormat();
|
||||||
|
format.setLineHeight(130, QTextBlockFormat::ProportionalHeight);
|
||||||
|
|
||||||
|
cursor.setBlockFormat(format);
|
||||||
|
|
||||||
|
ui->messagePlainTextEdit->setTextCursor(cursor);
|
||||||
|
|
||||||
if (!AccountManager::getInstance().isLoggedIn()) {
|
if (!AccountManager::getInstance().isLoggedIn()) {
|
||||||
ui->connectingToXMPPLabel->setText(tr("You must be logged in to chat with others."));
|
ui->connectingToXMPPLabel->setText(tr("You must be logged in to chat with others."));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_QXMPP
|
#ifdef HAVE_QXMPP
|
||||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||||
if (xmppClient.isConnected()) {
|
if (xmppClient.isConnected()) {
|
||||||
|
@ -89,36 +95,17 @@ ChatWindow::~ChatWindow() {
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatWindow::mousePressEvent(QMouseEvent *e) {
|
|
||||||
if (e->button() == Qt::LeftButton && isFloating()) {
|
|
||||||
_mousePressed = true;
|
|
||||||
_mouseStartPosition = e->pos();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatWindow::mouseMoveEvent(QMouseEvent *e) {
|
|
||||||
if (_mousePressed) {
|
|
||||||
move(mapToParent(e->pos() - _mouseStartPosition));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatWindow::mouseReleaseEvent( QMouseEvent *e ) {
|
|
||||||
if ( e->button() == Qt::LeftButton ) {
|
|
||||||
_mousePressed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatWindow::keyPressEvent(QKeyEvent* event) {
|
void ChatWindow::keyPressEvent(QKeyEvent* event) {
|
||||||
QDockWidget::keyPressEvent(event);
|
|
||||||
if (event->key() == Qt::Key_Escape) {
|
if (event->key() == Qt::Key_Escape) {
|
||||||
hide();
|
hide();
|
||||||
|
} else {
|
||||||
|
FramelessDialog::keyPressEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatWindow::showEvent(QShowEvent* event) {
|
void ChatWindow::showEvent(QShowEvent* event) {
|
||||||
QDockWidget::showEvent(event);
|
FramelessDialog::showEvent(event);
|
||||||
if (!event->spontaneous()) {
|
if (!event->spontaneous()) {
|
||||||
activateWindow();
|
|
||||||
ui->messagePlainTextEdit->setFocus();
|
ui->messagePlainTextEdit->setFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,18 +128,20 @@ bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
|
||||||
message.setBody(messageText);
|
message.setBody(messageText);
|
||||||
XmppClient::getInstance().getXMPPClient().sendPacket(message);
|
XmppClient::getInstance().getXMPPClient().sendPacket(message);
|
||||||
#endif
|
#endif
|
||||||
ui->messagePlainTextEdit->document()->clear();
|
QTextCursor cursor = ui->messagePlainTextEdit->textCursor();
|
||||||
|
cursor.select(QTextCursor::Document);
|
||||||
|
cursor.removeSelectedText();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (event->type() == QEvent::MouseButtonRelease) {
|
||||||
if (event->type() != QEvent::MouseButtonRelease) {
|
QVariant userVar = sender->property("user");
|
||||||
return false;
|
if (userVar.isValid()) {
|
||||||
|
Menu::getInstance()->goToUser("@" + userVar.toString());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
QString user = sender->property("user").toString();
|
|
||||||
Menu::getInstance()->goToUser(user);
|
|
||||||
}
|
}
|
||||||
return false;
|
return FramelessDialog::eventFilter(sender, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_QXMPP
|
#ifdef HAVE_QXMPP
|
||||||
|
@ -175,16 +164,17 @@ void ChatWindow::addTimeStamp() {
|
||||||
timeString.chop(1);
|
timeString.chop(1);
|
||||||
if (!timeString.isEmpty()) {
|
if (!timeString.isEmpty()) {
|
||||||
QLabel* timeLabel = new QLabel(timeString);
|
QLabel* timeLabel = new QLabel(timeString);
|
||||||
timeLabel->setStyleSheet("color: palette(shadow);"
|
timeLabel->setStyleSheet("color: #333333;"
|
||||||
"background-color: palette(highlight);"
|
"background-color: white;"
|
||||||
|
"font-size: 14pt;"
|
||||||
"padding: 4px;");
|
"padding: 4px;");
|
||||||
timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||||
timeLabel->setAlignment(Qt::AlignHCenter);
|
timeLabel->setAlignment(Qt::AlignLeft);
|
||||||
|
|
||||||
bool atBottom = isAtBottom();
|
bool atBottom = isNearBottom();
|
||||||
|
|
||||||
ui->messagesGridLayout->addWidget(timeLabel, ui->messagesGridLayout->rowCount(), 0, 1, 2);
|
ui->messagesVBoxLayout->addWidget(timeLabel);
|
||||||
ui->messagesGridLayout->parentWidget()->updateGeometry();
|
ui->messagesVBoxLayout->parentWidget()->updateGeometry();
|
||||||
|
|
||||||
Application::processEvents();
|
Application::processEvents();
|
||||||
numMessagesAfterLastTimeStamp = 0;
|
numMessagesAfterLastTimeStamp = 0;
|
||||||
|
@ -249,6 +239,7 @@ void ChatWindow::participantsChanged() {
|
||||||
"padding-bottom: 2px;"
|
"padding-bottom: 2px;"
|
||||||
"padding-left: 2px;"
|
"padding-left: 2px;"
|
||||||
"border: 1px solid palette(shadow);"
|
"border: 1px solid palette(shadow);"
|
||||||
|
"font-size: 14pt;"
|
||||||
"font-weight: bold");
|
"font-weight: bold");
|
||||||
userLabel->setProperty("user", participantName);
|
userLabel->setProperty("user", participantName);
|
||||||
userLabel->setCursor(Qt::PointingHandCursor);
|
userLabel->setCursor(Qt::PointingHandCursor);
|
||||||
|
@ -262,15 +253,11 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QLabel* userLabel = new QLabel(getParticipantName(message.from()));
|
// Update background if this is a message from the current user
|
||||||
userLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
bool fromSelf = getParticipantName(message.from()) == AccountManager::getInstance().getUsername();
|
||||||
userLabel->setStyleSheet("padding: 2px; font-weight: bold");
|
|
||||||
userLabel->setAlignment(Qt::AlignTop | Qt::AlignRight);
|
|
||||||
|
|
||||||
ChatMessageArea* messageArea = new ChatMessageArea();
|
// Create message area
|
||||||
|
ChatMessageArea* messageArea = new ChatMessageArea(true);
|
||||||
messageArea->setOpenLinks(true);
|
|
||||||
messageArea->setOpenExternalLinks(true);
|
|
||||||
messageArea->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
|
messageArea->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
|
||||||
messageArea->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
messageArea->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||||
messageArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
messageArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
@ -281,22 +268,30 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
|
||||||
"padding-left: 2px;"
|
"padding-left: 2px;"
|
||||||
"padding-top: 2px;"
|
"padding-top: 2px;"
|
||||||
"padding-right: 20px;"
|
"padding-right: 20px;"
|
||||||
|
"margin: 0px;"
|
||||||
|
"color: #333333;"
|
||||||
|
"font-size: 14pt;"
|
||||||
"background-color: rgba(0, 0, 0, 0%);"
|
"background-color: rgba(0, 0, 0, 0%);"
|
||||||
"border: 0;");
|
"border: 0;");
|
||||||
|
|
||||||
bool fromSelf = getParticipantName(message.from()) == AccountManager::getInstance().getUsername();
|
QString userLabel = getParticipantName(message.from());
|
||||||
if (fromSelf) {
|
if (fromSelf) {
|
||||||
userLabel->setStyleSheet(userLabel->styleSheet() + "; background-color: #e1e8ea");
|
userLabel = "<b style=\"color: #4a6f91\">" + userLabel + ": </b>";
|
||||||
messageArea->setStyleSheet(messageArea->styleSheet() + "; background-color: #e1e8ea");
|
messageArea->setStyleSheet(messageArea->styleSheet() + "background-color: #e1e8ea");
|
||||||
|
} else {
|
||||||
|
userLabel = "<b>" + userLabel + ": </b>";
|
||||||
}
|
}
|
||||||
|
|
||||||
messageArea->setHtml(message.body().replace(regexLinks, "<a href=\"\\1\">\\1</a>"));
|
messageArea->document()->setDefaultStyleSheet("a { text-decoration: none; font-weight: bold; color: #267077;}");
|
||||||
|
QString messageText = message.body().toHtmlEscaped();
|
||||||
|
messageText = messageText.replace(regexLinks, "<a href=\"\\1\">\\1</a>");
|
||||||
|
messageText = messageText.replace(regexHifiLinks, "<a href=\"hifi://\\1\">\\1</a>");
|
||||||
|
messageArea->setHtml(userLabel + messageText);
|
||||||
|
|
||||||
bool atBottom = isAtBottom();
|
bool atBottom = isNearBottom();
|
||||||
ui->messagesGridLayout->addWidget(userLabel, ui->messagesGridLayout->rowCount(), 0);
|
|
||||||
ui->messagesGridLayout->addWidget(messageArea, ui->messagesGridLayout->rowCount() - 1, 1);
|
|
||||||
|
|
||||||
ui->messagesGridLayout->parentWidget()->updateGeometry();
|
ui->messagesVBoxLayout->addWidget(messageArea);
|
||||||
|
ui->messagesVBoxLayout->parentWidget()->updateGeometry();
|
||||||
Application::processEvents();
|
Application::processEvents();
|
||||||
|
|
||||||
if (atBottom || fromSelf) {
|
if (atBottom || fromSelf) {
|
||||||
|
@ -313,26 +308,13 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool ChatWindow::isAtBottom() {
|
bool ChatWindow::isNearBottom() {
|
||||||
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
|
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
|
||||||
return verticalScrollBar->sliderPosition() == verticalScrollBar->maximum();
|
return verticalScrollBar->value() >= verticalScrollBar->maximum() - Ui::AUTO_SCROLL_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scroll chat message area to bottom.
|
// Scroll chat message area to bottom.
|
||||||
void ChatWindow::scrollToBottom() {
|
void ChatWindow::scrollToBottom() {
|
||||||
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
|
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
|
||||||
verticalScrollBar->setSliderPosition(verticalScrollBar->maximum());
|
verticalScrollBar->setValue(verticalScrollBar->maximum());
|
||||||
}
|
|
||||||
|
|
||||||
void ChatWindow::togglePinned() {
|
|
||||||
QMainWindow* mainWindow = Application::getInstance()->getWindow();
|
|
||||||
mainWindow->removeDockWidget(this);
|
|
||||||
if (ui->togglePinnedButton->isChecked()) {
|
|
||||||
mainWindow->addDockWidget(ui->togglePinnedButton->isChecked() ? Qt::RightDockWidgetArea : Qt::NoDockWidgetArea, this);
|
|
||||||
}
|
|
||||||
if (!this->toggleViewAction()->isChecked()) {
|
|
||||||
this->toggleViewAction()->trigger();
|
|
||||||
}
|
|
||||||
this->setFloating(!ui->togglePinnedButton->isChecked());
|
|
||||||
setTitleBarWidget(ui->togglePinnedButton->isChecked()?new QWidget():titleBar);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
|
#include "FramelessDialog.h"
|
||||||
|
|
||||||
#ifdef HAVE_QXMPP
|
#ifdef HAVE_QXMPP
|
||||||
|
|
||||||
|
@ -26,37 +27,38 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
|
|
||||||
|
// Maximum amount the chat can be scrolled up in order to auto scroll.
|
||||||
|
const int AUTO_SCROLL_THRESHOLD = 20;
|
||||||
|
|
||||||
|
|
||||||
class ChatWindow;
|
class ChatWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatWindow : public QDockWidget {
|
class ChatWindow : public FramelessDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ChatWindow();
|
ChatWindow(QWidget* parent);
|
||||||
~ChatWindow();
|
~ChatWindow();
|
||||||
|
|
||||||
virtual void keyPressEvent(QKeyEvent *event);
|
|
||||||
virtual void showEvent(QShowEvent* event);
|
|
||||||
|
|
||||||
virtual void mousePressEvent(QMouseEvent *e);
|
|
||||||
virtual void mouseMoveEvent(QMouseEvent *e);
|
|
||||||
virtual void mouseReleaseEvent(QMouseEvent *e);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool eventFilter(QObject* sender, QEvent* event);
|
bool eventFilter(QObject* sender, QEvent* event);
|
||||||
|
|
||||||
|
virtual void keyPressEvent(QKeyEvent *event);
|
||||||
|
virtual void showEvent(QShowEvent* event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef HAVE_QXMPP
|
#ifdef HAVE_QXMPP
|
||||||
QString getParticipantName(const QString& participant);
|
QString getParticipantName(const QString& participant);
|
||||||
#endif
|
#endif
|
||||||
void startTimerForTimeStamps();
|
void startTimerForTimeStamps();
|
||||||
void addTimeStamp();
|
void addTimeStamp();
|
||||||
bool isAtBottom();
|
bool isNearBottom();
|
||||||
void scrollToBottom();
|
void scrollToBottom();
|
||||||
|
|
||||||
Ui::ChatWindow* ui;
|
Ui::ChatWindow* ui;
|
||||||
QWidget* titleBar;
|
|
||||||
int numMessagesAfterLastTimeStamp;
|
int numMessagesAfterLastTimeStamp;
|
||||||
QDateTime lastMessageStamp;
|
QDateTime lastMessageStamp;
|
||||||
bool _mousePressed;
|
bool _mousePressed;
|
||||||
|
@ -65,7 +67,6 @@ private:
|
||||||
private slots:
|
private slots:
|
||||||
void connected();
|
void connected();
|
||||||
void timeout();
|
void timeout();
|
||||||
void togglePinned();
|
|
||||||
#ifdef HAVE_QXMPP
|
#ifdef HAVE_QXMPP
|
||||||
void error(QXmppClient::Error error);
|
void error(QXmppClient::Error error);
|
||||||
void participantsChanged();
|
void participantsChanged();
|
||||||
|
|
|
@ -14,8 +14,13 @@
|
||||||
|
|
||||||
const int RESIZE_HANDLE_WIDTH = 7;
|
const int RESIZE_HANDLE_WIDTH = 7;
|
||||||
|
|
||||||
FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags) :
|
FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags, Position position) :
|
||||||
QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) {
|
QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint),
|
||||||
|
_isResizing(false),
|
||||||
|
_resizeInitialWidth(0),
|
||||||
|
_selfHidden(false),
|
||||||
|
_position(position) {
|
||||||
|
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
// handle rezize and move events
|
// handle rezize and move events
|
||||||
|
@ -29,29 +34,37 @@ bool FramelessDialog::eventFilter(QObject* sender, QEvent* event) {
|
||||||
switch (event->type()) {
|
switch (event->type()) {
|
||||||
case QEvent::Move:
|
case QEvent::Move:
|
||||||
if (sender == parentWidget()) {
|
if (sender == parentWidget()) {
|
||||||
// move to upper left corner on app move
|
resizeAndPosition(false);
|
||||||
move(parentWidget()->geometry().topLeft());
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QEvent::Resize:
|
case QEvent::Resize:
|
||||||
if (sender == parentWidget()) {
|
if (sender == parentWidget()) {
|
||||||
// keep full app height on resizing the app
|
resizeAndPosition(false);
|
||||||
setFixedHeight(parentWidget()->size().height());
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QEvent::WindowStateChange:
|
case QEvent::WindowStateChange:
|
||||||
if (parentWidget()->isMinimized()) {
|
if (parentWidget()->isMinimized()) {
|
||||||
setHidden(true);
|
if (isVisible()) {
|
||||||
} else {
|
_selfHidden = true;
|
||||||
|
setHidden(true);
|
||||||
|
}
|
||||||
|
} else if (_selfHidden) {
|
||||||
|
_selfHidden = false;
|
||||||
setHidden(false);
|
setHidden(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QEvent::ApplicationDeactivate:
|
case QEvent::ApplicationDeactivate:
|
||||||
// hide on minimize and focus lost
|
// hide on minimize and focus lost
|
||||||
setHidden(true);
|
if (isVisible()) {
|
||||||
|
_selfHidden = true;
|
||||||
|
setHidden(true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case QEvent::ApplicationActivate:
|
case QEvent::ApplicationActivate:
|
||||||
setHidden(false);
|
if (_selfHidden) {
|
||||||
|
_selfHidden = false;
|
||||||
|
setHidden(false);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -70,21 +83,38 @@ void FramelessDialog::setStyleSheetFile(const QString& fileName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramelessDialog::showEvent(QShowEvent* event) {
|
void FramelessDialog::showEvent(QShowEvent* event) {
|
||||||
// move to upper left corner
|
resizeAndPosition();
|
||||||
move(parentWidget()->geometry().topLeft());
|
}
|
||||||
|
|
||||||
|
void FramelessDialog::resizeAndPosition(bool resizeParent) {
|
||||||
// keep full app height
|
// keep full app height
|
||||||
setFixedHeight(parentWidget()->size().height());
|
setFixedHeight(parentWidget()->size().height());
|
||||||
|
|
||||||
// resize parrent if width is smaller than this dialog
|
// resize parrent if width is smaller than this dialog
|
||||||
if (parentWidget()->size().width() < size().width()) {
|
if (resizeParent && parentWidget()->size().width() < size().width()) {
|
||||||
parentWidget()->resize(size().width(), parentWidget()->size().height());
|
parentWidget()->resize(size().width(), parentWidget()->size().height());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_position == POSITION_LEFT) {
|
||||||
|
// move to upper left corner
|
||||||
|
move(parentWidget()->geometry().topLeft());
|
||||||
|
} else if (_position == POSITION_RIGHT) {
|
||||||
|
// move to upper right corner
|
||||||
|
QPoint pos = parentWidget()->geometry().topRight();
|
||||||
|
pos.setX(pos.x() - size().width());
|
||||||
|
move(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) {
|
void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) {
|
||||||
if (abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH && mouseEvent->button() == Qt::LeftButton) {
|
if (mouseEvent->button() == Qt::LeftButton) {
|
||||||
_isResizing = true;
|
bool hitLeft = _position == POSITION_LEFT && abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH;
|
||||||
QApplication::setOverrideCursor(Qt::SizeHorCursor);
|
bool hitRight = _position == POSITION_RIGHT && mouseEvent->pos().x() < RESIZE_HANDLE_WIDTH;
|
||||||
|
if (hitLeft || hitRight) {
|
||||||
|
_isResizing = true;
|
||||||
|
_resizeInitialWidth = size().width();
|
||||||
|
QApplication::setOverrideCursor(Qt::SizeHorCursor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +125,14 @@ void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) {
|
||||||
|
|
||||||
void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) {
|
void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) {
|
||||||
if (_isResizing) {
|
if (_isResizing) {
|
||||||
resize(mouseEvent->pos().x(), size().height());
|
if (_position == POSITION_LEFT) {
|
||||||
|
resize(mouseEvent->pos().x(), size().height());
|
||||||
|
} else if (_position == POSITION_RIGHT) {
|
||||||
|
setUpdatesEnabled(false);
|
||||||
|
resize(_resizeInitialWidth - mouseEvent->pos().x(), size().height());
|
||||||
|
resizeAndPosition();
|
||||||
|
_resizeInitialWidth = size().width();
|
||||||
|
setUpdatesEnabled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,9 @@ class FramelessDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FramelessDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0);
|
enum Position { POSITION_LEFT, POSITION_RIGHT };
|
||||||
|
|
||||||
|
FramelessDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0, Position position = POSITION_LEFT);
|
||||||
void setStyleSheetFile(const QString& fileName);
|
void setStyleSheetFile(const QString& fileName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -31,7 +33,12 @@ protected:
|
||||||
bool eventFilter(QObject* sender, QEvent* event);
|
bool eventFilter(QObject* sender, QEvent* event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void resizeAndPosition(bool resizeParent = true);
|
||||||
|
|
||||||
bool _isResizing;
|
bool _isResizing;
|
||||||
|
int _resizeInitialWidth;
|
||||||
|
bool _selfHidden; ///< true when the dialog itself because of a window event (deactivation or minimization)
|
||||||
|
Position _position;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ const int SCROLL_PANEL_BOTTOM_MARGIN = 30;
|
||||||
const int OK_BUTTON_RIGHT_MARGIN = 30;
|
const int OK_BUTTON_RIGHT_MARGIN = 30;
|
||||||
const int BUTTONS_TOP_MARGIN = 24;
|
const int BUTTONS_TOP_MARGIN = 24;
|
||||||
|
|
||||||
PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : FramelessDialog(parent, flags) {
|
PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : FramelessDialog(parent, flags, POSITION_LEFT) {
|
||||||
|
|
||||||
ui.setupUi(this);
|
ui.setupUi(this);
|
||||||
setStyleSheetFile("styles/preferences.qss");
|
setStyleSheetFile("styles/preferences.qss");
|
||||||
|
@ -38,26 +38,34 @@ void PreferencesDialog::accept() {
|
||||||
|
|
||||||
void PreferencesDialog::setHeadUrl(QString modelUrl) {
|
void PreferencesDialog::setHeadUrl(QString modelUrl) {
|
||||||
ui.faceURLEdit->setText(modelUrl);
|
ui.faceURLEdit->setText(modelUrl);
|
||||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreferencesDialog::setSkeletonUrl(QString modelUrl) {
|
void PreferencesDialog::setSkeletonUrl(QString modelUrl) {
|
||||||
ui.skeletonURLEdit->setText(modelUrl);
|
ui.skeletonURLEdit->setText(modelUrl);
|
||||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreferencesDialog::openHeadModelBrowser() {
|
void PreferencesDialog::openHeadModelBrowser() {
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
|
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
|
||||||
|
show();
|
||||||
|
|
||||||
ModelsBrowser modelBrowser(Head);
|
ModelsBrowser modelBrowser(Head);
|
||||||
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setHeadUrl);
|
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setHeadUrl);
|
||||||
modelBrowser.browse();
|
modelBrowser.browse();
|
||||||
|
|
||||||
|
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||||
|
show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreferencesDialog::openBodyModelBrowser() {
|
void PreferencesDialog::openBodyModelBrowser() {
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
|
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
|
||||||
|
show();
|
||||||
|
|
||||||
ModelsBrowser modelBrowser(Skeleton);
|
ModelsBrowser modelBrowser(Skeleton);
|
||||||
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setSkeletonUrl);
|
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setSkeletonUrl);
|
||||||
modelBrowser.browse();
|
modelBrowser.browse();
|
||||||
|
|
||||||
|
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||||
|
show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreferencesDialog::openSnapshotLocationBrowser() {
|
void PreferencesDialog::openSnapshotLocationBrowser() {
|
||||||
|
@ -176,6 +184,7 @@ void PreferencesDialog::savePreferences() {
|
||||||
Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value());
|
Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value());
|
||||||
|
|
||||||
Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value());
|
Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value());
|
||||||
|
Application::getInstance()->getAudio()->setJitterBufferSamples(ui.audioJitterSpin->value());
|
||||||
|
|
||||||
Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(),
|
Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(),
|
||||||
Application::getInstance()->getGLWidget()->height());
|
Application::getInstance()->getGLWidget()->height());
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>ChatWindow</class>
|
<class>ChatWindow</class>
|
||||||
<widget class="QDockWidget" name="ChatWindow">
|
<widget class="QDialog" name="ChatWindow">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>400</width>
|
||||||
<height>608</height>
|
<height>440</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
|
@ -16,127 +16,95 @@
|
||||||
<height>238</height>
|
<height>238</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">font-family: Helvetica, Arial, sans-serif;</string>
|
|
||||||
</property>
|
|
||||||
<property name="features">
|
|
||||||
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
|
|
||||||
</property>
|
|
||||||
<property name="allowedAreas">
|
|
||||||
<set>Qt::NoDockWidgetArea</set>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Chat</string>
|
<string>Chat</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="dockWidgetContents">
|
<property name="styleSheet">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<string notr="true">font-family: Helvetica, Arial, sans-serif;</string>
|
||||||
<property name="spacing">
|
</property>
|
||||||
<number>0</number>
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
</property>
|
<property name="leftMargin">
|
||||||
<property name="leftMargin">
|
<number>0</number>
|
||||||
<number>8</number>
|
</property>
|
||||||
</property>
|
<property name="topMargin">
|
||||||
<property name="topMargin">
|
<number>0</number>
|
||||||
<number>8</number>
|
</property>
|
||||||
</property>
|
<property name="rightMargin">
|
||||||
<property name="rightMargin">
|
<number>0</number>
|
||||||
<number>8</number>
|
</property>
|
||||||
</property>
|
<property name="bottomMargin">
|
||||||
<property name="bottomMargin">
|
<number>0</number>
|
||||||
<number>8</number>
|
</property>
|
||||||
</property>
|
<item row="0" column="0">
|
||||||
<item>
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<widget class="QLabel" name="connectingToXMPPLabel">
|
<property name="spacing">
|
||||||
<property name="sizePolicy">
|
<number>0</number>
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
</property>
|
||||||
<horstretch>0</horstretch>
|
<property name="leftMargin">
|
||||||
<verstretch>0</verstretch>
|
<number>8</number>
|
||||||
</sizepolicy>
|
</property>
|
||||||
</property>
|
<property name="topMargin">
|
||||||
<property name="text">
|
<number>8</number>
|
||||||
<string>Connecting to XMPP...</string>
|
</property>
|
||||||
</property>
|
<property name="rightMargin">
|
||||||
<property name="alignment">
|
<number>8</number>
|
||||||
<set>Qt::AlignCenter</set>
|
</property>
|
||||||
</property>
|
<property name="bottomMargin">
|
||||||
</widget>
|
<number>8</number>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<widget class="QLabel" name="connectingToXMPPLabel">
|
||||||
<item>
|
<property name="sizePolicy">
|
||||||
<widget class="QLabel" name="numOnlineLabel">
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
<property name="sizePolicy">
|
<horstretch>0</horstretch>
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
<verstretch>0</verstretch>
|
||||||
<horstretch>0</horstretch>
|
</sizepolicy>
|
||||||
<verstretch>0</verstretch>
|
</property>
|
||||||
</sizepolicy>
|
<property name="text">
|
||||||
</property>
|
<string>Connecting to XMPP...</string>
|
||||||
<property name="styleSheet">
|
</property>
|
||||||
<string notr="true">font-weight: bold; color: palette(shadow); margin-bottom: 4px;</string>
|
<property name="alignment">
|
||||||
</property>
|
<set>Qt::AlignCenter</set>
|
||||||
<property name="text">
|
</property>
|
||||||
<string> online now:</string>
|
</widget>
|
||||||
</property>
|
</item>
|
||||||
</widget>
|
<item>
|
||||||
</item>
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="togglePinnedButton">
|
<widget class="QLabel" name="numOnlineLabel">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximumSize">
|
<property name="styleSheet">
|
||||||
<size>
|
<string notr="true">font-weight: bold; color: palette(shadow); margin-bottom: 4px;</string>
|
||||||
<width>16</width>
|
</property>
|
||||||
<height>16</height>
|
<property name="text">
|
||||||
</size>
|
<string> online now:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="focusPolicy">
|
</widget>
|
||||||
<enum>Qt::NoFocus</enum>
|
</item>
|
||||||
</property>
|
<item>
|
||||||
<property name="text">
|
<widget class="QPushButton" name="closeButton">
|
||||||
<string/>
|
<property name="sizePolicy">
|
||||||
</property>
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
<property name="icon">
|
<horstretch>0</horstretch>
|
||||||
<iconset>
|
<verstretch>0</verstretch>
|
||||||
<normaloff>../resources/images/pin.svg</normaloff>
|
</sizepolicy>
|
||||||
<normalon>../resources/images/pinned.svg</normalon>../resources/images/pin.svg</iconset>
|
</property>
|
||||||
</property>
|
<property name="maximumSize">
|
||||||
<property name="checkable">
|
<size>
|
||||||
<bool>true</bool>
|
<width>16</width>
|
||||||
</property>
|
<height>16</height>
|
||||||
<property name="checked">
|
</size>
|
||||||
<bool>true</bool>
|
</property>
|
||||||
</property>
|
<property name="focusPolicy">
|
||||||
<property name="default">
|
<enum>Qt::NoFocus</enum>
|
||||||
<bool>false</bool>
|
</property>
|
||||||
</property>
|
<property name="styleSheet">
|
||||||
<property name="flat">
|
<string notr="true">QPushButton {
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="closeButton">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>16</width>
|
|
||||||
<height>16</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="focusPolicy">
|
|
||||||
<enum>Qt::NoFocus</enum>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">QPushButton {
|
|
||||||
background-color: rgba( 0, 0, 0, 0% );
|
background-color: rgba( 0, 0, 0, 0% );
|
||||||
border: none;
|
border: none;
|
||||||
image: url(../resources/images/close.svg)
|
image: url(../resources/images/close.svg)
|
||||||
|
@ -148,50 +116,104 @@ QPushButton:pressed {
|
||||||
border: none;
|
border: none;
|
||||||
image: url(../resources/images/close_down.svg)
|
image: url(../resources/images/close_down.svg)
|
||||||
}</string>
|
}</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="flat">
|
<property name="flat">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QWidget" name="usersWidget" native="true"/>
|
<widget class="QWidget" name="usersWidget" native="true">
|
||||||
</item>
|
<property name="styleSheet">
|
||||||
<item>
|
<string notr="true">#usersWidget {
|
||||||
<widget class="QScrollArea" name="messagesScrollArea">
|
margin-right: 20px;
|
||||||
<property name="styleSheet">
|
}</string>
|
||||||
<string notr="true">margin-top: 12px;</string>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalScrollBarPolicy">
|
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
<property name="widgetResizable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>382</width>
|
|
||||||
<height>16</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="messagesScrollArea">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">margin-top: 12px;</string>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>382</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">margin-top: 0px;</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="messagesVBoxLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="chatFrame">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="styleSheet">
|
<property name="minimumSize">
|
||||||
<string notr="true">margin-top: 0px;</string>
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>78</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="messagesGridLayout">
|
<property name="styleSheet">
|
||||||
|
<string notr="true">#chatFrame {
|
||||||
|
border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;
|
||||||
|
}</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
|
@ -204,69 +226,65 @@ QPushButton:pressed {
|
||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="spacing">
|
<item>
|
||||||
<number>0</number>
|
<widget class="ChatInputArea" name="messagePlainTextEdit">
|
||||||
</property>
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Helvetica,Arial,sans-serif</family>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tabChangesFocus">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="acceptRichText">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</item>
|
||||||
</item>
|
</layout>
|
||||||
<item>
|
</item>
|
||||||
<widget class="QPlainTextEdit" name="messagePlainTextEdit">
|
</layout>
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>60</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;</string>
|
|
||||||
</property>
|
|
||||||
<property name="frameShape">
|
|
||||||
<enum>QFrame::NoFrame</enum>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalScrollBarPolicy">
|
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeAdjustPolicy">
|
|
||||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
|
||||||
</property>
|
|
||||||
<property name="tabChangesFocus">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>ChatInputArea</class>
|
||||||
|
<extends>QTextEdit</extends>
|
||||||
|
<header>ui/ChatInputArea.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>messagePlainTextEdit</tabstop>
|
|
||||||
<tabstop>messagesScrollArea</tabstop>
|
<tabstop>messagesScrollArea</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
|
||||||
<sender>togglePinnedButton</sender>
|
|
||||||
<signal>clicked()</signal>
|
|
||||||
<receiver>ChatWindow</receiver>
|
|
||||||
<slot>togglePinned()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>390</x>
|
|
||||||
<y>42</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>550</x>
|
|
||||||
<y>42</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
<connection>
|
||||||
<sender>closeButton</sender>
|
<sender>closeButton</sender>
|
||||||
<signal>clicked()</signal>
|
<signal>clicked()</signal>
|
||||||
|
|
|
@ -71,8 +71,8 @@ void AudioInjector::injectAudio() {
|
||||||
quint8 volume = MAX_INJECTOR_VOLUME * _options.getVolume();
|
quint8 volume = MAX_INJECTOR_VOLUME * _options.getVolume();
|
||||||
packetStream << volume;
|
packetStream << volume;
|
||||||
|
|
||||||
timeval startTime = {};
|
QElapsedTimer timer;
|
||||||
gettimeofday(&startTime, NULL);
|
timer.start();
|
||||||
int nextFrame = 0;
|
int nextFrame = 0;
|
||||||
|
|
||||||
int currentSendPosition = 0;
|
int currentSendPosition = 0;
|
||||||
|
@ -104,7 +104,7 @@ void AudioInjector::injectAudio() {
|
||||||
if (currentSendPosition != bytesToCopy && currentSendPosition < soundByteArray.size()) {
|
if (currentSendPosition != bytesToCopy && currentSendPosition < soundByteArray.size()) {
|
||||||
// not the first packet and not done
|
// not the first packet and not done
|
||||||
// sleep for the appropriate time
|
// sleep for the appropriate time
|
||||||
int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow();
|
int usecToSleep = (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - timer.nsecsElapsed() / 1000;
|
||||||
|
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
|
|
|
@ -282,10 +282,13 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas
|
||||||
QUrl grantURL = _authURL;
|
QUrl grantURL = _authURL;
|
||||||
grantURL.setPath("/oauth/token");
|
grantURL.setPath("/oauth/token");
|
||||||
|
|
||||||
|
const QString ACCOUNT_MANAGER_REQUESTED_SCOPE = "owner";
|
||||||
|
|
||||||
QByteArray postData;
|
QByteArray postData;
|
||||||
postData.append("grant_type=password&");
|
postData.append("grant_type=password&");
|
||||||
postData.append("username=" + login + "&");
|
postData.append("username=" + login + "&");
|
||||||
postData.append("password=" + password);
|
postData.append("password=" + password + "&");
|
||||||
|
postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE);
|
||||||
|
|
||||||
request.setUrl(grantURL);
|
request.setUrl(grantURL);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
|
|
|
@ -12,12 +12,6 @@
|
||||||
#ifndef hifi_Assignment_h
|
#ifndef hifi_Assignment_h
|
||||||
#define hifi_Assignment_h
|
#define hifi_Assignment_h
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include "Systime.h"
|
|
||||||
#else
|
|
||||||
#include <sys/time.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QtCore/QUuid>
|
#include <QtCore/QUuid>
|
||||||
|
|
||||||
#include "NodeList.h"
|
#include "NodeList.h"
|
||||||
|
|
|
@ -542,6 +542,19 @@ OctreeElement* Octree::getOctreeElementAt(float x, float y, float z, float s) co
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OctreeElement* Octree::getOctreeEnclosingElementAt(float x, float y, float z, float s) const {
|
||||||
|
unsigned char* octalCode = pointToOctalCode(x,y,z,s);
|
||||||
|
OctreeElement* node = nodeForOctalCode(_rootNode, octalCode, NULL);
|
||||||
|
|
||||||
|
delete[] octalCode; // cleanup memory
|
||||||
|
#ifdef HAS_AUDIT_CHILDREN
|
||||||
|
if (node) {
|
||||||
|
node->auditChildren("Octree::getOctreeElementAt()");
|
||||||
|
}
|
||||||
|
#endif // def HAS_AUDIT_CHILDREN
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
OctreeElement* Octree::getOrCreateChildElementAt(float x, float y, float z, float s) {
|
OctreeElement* Octree::getOrCreateChildElementAt(float x, float y, float z, float s) {
|
||||||
return getRoot()->getOrCreateChildElementAt(x, y, z, s);
|
return getRoot()->getOrCreateChildElementAt(x, y, z, s);
|
||||||
|
|
|
@ -210,7 +210,15 @@ public:
|
||||||
void reaverageOctreeElements(OctreeElement* startNode = NULL);
|
void reaverageOctreeElements(OctreeElement* startNode = NULL);
|
||||||
|
|
||||||
void deleteOctreeElementAt(float x, float y, float z, float s);
|
void deleteOctreeElementAt(float x, float y, float z, float s);
|
||||||
|
|
||||||
|
/// Find the voxel at position x,y,z,s
|
||||||
|
/// \return pointer to the OctreeElement or NULL if none at x,y,z,s.
|
||||||
OctreeElement* getOctreeElementAt(float x, float y, float z, float s) const;
|
OctreeElement* getOctreeElementAt(float x, float y, float z, float s) const;
|
||||||
|
|
||||||
|
/// Find the voxel at position x,y,z,s
|
||||||
|
/// \return pointer to the OctreeElement or to the smallest enclosing parent if none at x,y,z,s.
|
||||||
|
OctreeElement* getOctreeEnclosingElementAt(float x, float y, float z, float s) const;
|
||||||
|
|
||||||
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
||||||
|
|
||||||
void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL);
|
void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL);
|
||||||
|
|
|
@ -820,11 +820,7 @@ const char* OctreeSceneStats::getItemValue(Item item) {
|
||||||
|
|
||||||
void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
|
void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
|
||||||
bool wasStatsPacket, int nodeClockSkewUsec) {
|
bool wasStatsPacket, int nodeClockSkewUsec) {
|
||||||
_incomingPacket++;
|
const bool wantExtraDebugging = false;
|
||||||
_incomingBytes += packet.size();
|
|
||||||
if (!wasStatsPacket) {
|
|
||||||
_incomingWastedBytes += (MAX_PACKET_SIZE - packet.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
||||||
const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data()) + numBytesPacketHeader;
|
const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data()) + numBytesPacketHeader;
|
||||||
|
@ -842,12 +838,43 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
|
||||||
|
|
||||||
OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
|
OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
|
||||||
int flightTime = arrivedAt - sentAt + nodeClockSkewUsec;
|
int flightTime = arrivedAt - sentAt + nodeClockSkewUsec;
|
||||||
|
|
||||||
|
if (wantExtraDebugging) {
|
||||||
|
qDebug() << "sentAt:" << sentAt << " usecs";
|
||||||
|
qDebug() << "arrivedAt:" << arrivedAt << " usecs";
|
||||||
|
qDebug() << "nodeClockSkewUsec:" << nodeClockSkewUsec << " usecs";
|
||||||
|
qDebug() << "flightTime:" << flightTime << " usecs";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guard against possible corrupted packets... with bad timestamps
|
||||||
|
const int MAX_RESONABLE_FLIGHT_TIME = 200 * USECS_PER_SECOND; // 200 seconds is more than enough time for a packet to arrive
|
||||||
|
const int MIN_RESONABLE_FLIGHT_TIME = 0;
|
||||||
|
if (flightTime > MAX_RESONABLE_FLIGHT_TIME || flightTime < MIN_RESONABLE_FLIGHT_TIME) {
|
||||||
|
qDebug() << "ignoring unreasonable packet... flightTime:" << flightTime;
|
||||||
|
return; // ignore any packets that are unreasonable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guard against possible corrupted packets... with bad sequence numbers
|
||||||
|
const int MAX_RESONABLE_SEQUENCE_OFFSET = 2000;
|
||||||
|
const int MIN_RESONABLE_SEQUENCE_OFFSET = -2000;
|
||||||
|
int sequenceOffset = (sequence - _incomingLastSequence);
|
||||||
|
if (sequenceOffset > MAX_RESONABLE_SEQUENCE_OFFSET || sequenceOffset < MIN_RESONABLE_SEQUENCE_OFFSET) {
|
||||||
|
qDebug() << "ignoring unreasonable packet... sequence:" << sequence << "_incomingLastSequence:" << _incomingLastSequence;
|
||||||
|
return; // ignore any packets that are unreasonable
|
||||||
|
}
|
||||||
|
|
||||||
|
// track packets here...
|
||||||
|
_incomingPacket++;
|
||||||
|
_incomingBytes += packet.size();
|
||||||
|
if (!wasStatsPacket) {
|
||||||
|
_incomingWastedBytes += (MAX_PACKET_SIZE - packet.size());
|
||||||
|
}
|
||||||
|
|
||||||
const int USECS_PER_MSEC = 1000;
|
const int USECS_PER_MSEC = 1000;
|
||||||
float flightTimeMsecs = flightTime / USECS_PER_MSEC;
|
float flightTimeMsecs = flightTime / USECS_PER_MSEC;
|
||||||
_incomingFlightTimeAverage.updateAverage(flightTimeMsecs);
|
_incomingFlightTimeAverage.updateAverage(flightTimeMsecs);
|
||||||
|
|
||||||
// track out of order and possibly lost packets...
|
// track out of order and possibly lost packets...
|
||||||
const bool wantExtraDebugging = false;
|
|
||||||
if (sequence == _incomingLastSequence) {
|
if (sequence == _incomingLastSequence) {
|
||||||
if (wantExtraDebugging) {
|
if (wantExtraDebugging) {
|
||||||
qDebug() << "last packet duplicate got:" << sequence << "_incomingLastSequence:" << _incomingLastSequence;
|
qDebug() << "last packet duplicate got:" << sequence << "_incomingLastSequence:" << _incomingLastSequence;
|
||||||
|
|
|
@ -294,8 +294,8 @@ void ScriptEngine::run() {
|
||||||
emit errorMessage("Uncaught exception at line" + QString::number(line) + ":" + result.toString());
|
emit errorMessage("Uncaught exception at line" + QString::number(line) + ":" + result.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
timeval startTime;
|
QElapsedTimer startTime;
|
||||||
gettimeofday(&startTime, NULL);
|
startTime.start();
|
||||||
|
|
||||||
int thisFrame = 0;
|
int thisFrame = 0;
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ void ScriptEngine::run() {
|
||||||
qint64 lastUpdate = usecTimestampNow();
|
qint64 lastUpdate = usecTimestampNow();
|
||||||
|
|
||||||
while (!_isFinished) {
|
while (!_isFinished) {
|
||||||
int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - usecTimestampNow();
|
int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include "Systime.h"
|
|
||||||
#else
|
|
||||||
#include <sys/time.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
|
@ -15,28 +15,39 @@
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
#include "OctalCode.h"
|
#include "OctalCode.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
quint64 usecTimestamp(const timeval *time) {
|
static int usecTimestampNowAdjust = 0; // in usec
|
||||||
return (time->tv_sec * 1000000 + time->tv_usec);
|
|
||||||
}
|
|
||||||
|
|
||||||
int usecTimestampNowAdjust = 0;
|
|
||||||
void usecTimestampNowForceClockSkew(int clockSkew) {
|
void usecTimestampNowForceClockSkew(int clockSkew) {
|
||||||
::usecTimestampNowAdjust = clockSkew;
|
::usecTimestampNowAdjust = clockSkew;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 usecTimestampNow() {
|
quint64 usecTimestampNow() {
|
||||||
timeval now;
|
static bool usecTimestampNowIsInitialized = false;
|
||||||
gettimeofday(&now, NULL);
|
static qint64 TIME_REFERENCE = 0; // in usec
|
||||||
return (now.tv_sec * 1000000 + now.tv_usec) + ::usecTimestampNowAdjust;
|
static QElapsedTimer timestampTimer;
|
||||||
|
|
||||||
|
if (!usecTimestampNowIsInitialized) {
|
||||||
|
TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * 1000; // ms to usec
|
||||||
|
timestampTimer.start();
|
||||||
|
usecTimestampNowIsInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// usec nsec to usec usec
|
||||||
|
return TIME_REFERENCE + timestampTimer.nsecsElapsed() / 1000 + ::usecTimestampNowAdjust;
|
||||||
}
|
}
|
||||||
|
|
||||||
float randFloat() {
|
float randFloat() {
|
||||||
|
@ -640,27 +651,59 @@ void debug::checkDeadBeef(void* memoryVoid, int size) {
|
||||||
// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
|
// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
|
||||||
glm::vec3 safeEulerAngles(const glm::quat& q) {
|
glm::vec3 safeEulerAngles(const glm::quat& q) {
|
||||||
float sy = 2.0f * (q.y * q.w - q.x * q.z);
|
float sy = 2.0f * (q.y * q.w - q.x * q.z);
|
||||||
|
glm::vec3 eulers;
|
||||||
if (sy < 1.0f - EPSILON) {
|
if (sy < 1.0f - EPSILON) {
|
||||||
if (sy > -1.0f + EPSILON) {
|
if (sy > -1.0f + EPSILON) {
|
||||||
return glm::vec3(
|
eulers = glm::vec3(
|
||||||
atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)),
|
atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)),
|
||||||
asinf(sy),
|
asinf(sy),
|
||||||
atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z)));
|
atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z)));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// not a unique solution; x + z = atan2(-m21, m11)
|
// not a unique solution; x + z = atan2(-m21, m11)
|
||||||
return glm::vec3(
|
eulers = glm::vec3(
|
||||||
0.0f,
|
0.0f,
|
||||||
- PI_OVER_TWO,
|
- PI_OVER_TWO,
|
||||||
atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)));
|
atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// not a unique solution; x - z = atan2(-m21, m11)
|
// not a unique solution; x - z = atan2(-m21, m11)
|
||||||
return glm::vec3(
|
eulers = glm::vec3(
|
||||||
0.0f,
|
0.0f,
|
||||||
PI_OVER_TWO,
|
PI_OVER_TWO,
|
||||||
-atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)));
|
-atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// adjust so that z, rather than y, is in [-pi/2, pi/2]
|
||||||
|
if (eulers.z < -PI_OVER_TWO) {
|
||||||
|
if (eulers.x < 0.0f) {
|
||||||
|
eulers.x += PI;
|
||||||
|
} else {
|
||||||
|
eulers.x -= PI;
|
||||||
|
}
|
||||||
|
eulers.y = -eulers.y;
|
||||||
|
if (eulers.y < 0.0f) {
|
||||||
|
eulers.y += PI;
|
||||||
|
} else {
|
||||||
|
eulers.y -= PI;
|
||||||
|
}
|
||||||
|
eulers.z += PI;
|
||||||
|
|
||||||
|
} else if (eulers.z > PI_OVER_TWO) {
|
||||||
|
if (eulers.x < 0.0f) {
|
||||||
|
eulers.x += PI;
|
||||||
|
} else {
|
||||||
|
eulers.x -= PI;
|
||||||
|
}
|
||||||
|
eulers.y = -eulers.y;
|
||||||
|
if (eulers.y < 0.0f) {
|
||||||
|
eulers.y += PI;
|
||||||
|
} else {
|
||||||
|
eulers.y -= PI;
|
||||||
|
}
|
||||||
|
eulers.z -= PI;
|
||||||
|
}
|
||||||
|
return eulers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function returns the positive angle (in radians) between two 3D vectors
|
// Helper function returns the positive angle (in radians) between two 3D vectors
|
||||||
|
|
|
@ -24,12 +24,6 @@
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include "Systime.h"
|
|
||||||
#else
|
|
||||||
#include <sys/time.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const int BYTES_PER_COLOR = 3;
|
const int BYTES_PER_COLOR = 3;
|
||||||
const int BYTES_PER_FLAGS = 1;
|
const int BYTES_PER_FLAGS = 1;
|
||||||
typedef unsigned char rgbColor[BYTES_PER_COLOR];
|
typedef unsigned char rgbColor[BYTES_PER_COLOR];
|
||||||
|
@ -66,7 +60,6 @@ static const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND;
|
||||||
|
|
||||||
const int BITS_IN_BYTE = 8;
|
const int BITS_IN_BYTE = 8;
|
||||||
|
|
||||||
quint64 usecTimestamp(const timeval *time);
|
|
||||||
quint64 usecTimestampNow();
|
quint64 usecTimestampNow();
|
||||||
void usecTimestampNowForceClockSkew(int clockSkew);
|
void usecTimestampNowForceClockSkew(int clockSkew);
|
||||||
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
//
|
|
||||||
// Systime.cpp
|
|
||||||
// libraries/shared/src
|
|
||||||
//
|
|
||||||
// Copyright 2013 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
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
|
|
||||||
#include "Systime.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gettimeofday
|
|
||||||
* Implementation according to:
|
|
||||||
* The Open Group Base Specifications Issue 6
|
|
||||||
* IEEE Std 1003.1, 2004 Edition
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* THIS SOFTWARE IS NOT COPYRIGHTED
|
|
||||||
*
|
|
||||||
* This source code is offered for use in the public domain. You may
|
|
||||||
* use, modify or distribute it freely.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful but
|
|
||||||
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
|
|
||||||
* DISCLAIMED. This includes but is not limited to warranties of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* Contributed by:
|
|
||||||
* Danny Smith <dannysmith@users.sourceforge.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
/** Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
|
|
||||||
#define _W32_FT_OFFSET (116444736000000000ULL)
|
|
||||||
|
|
||||||
int gettimeofday(timeval* p_tv, timezone* p_tz) {
|
|
||||||
|
|
||||||
union {
|
|
||||||
unsigned long long ns100; /**time since 1 Jan 1601 in 100ns units */
|
|
||||||
FILETIME ft;
|
|
||||||
} _now;
|
|
||||||
|
|
||||||
if (p_tv) {
|
|
||||||
GetSystemTimeAsFileTime (&_now.ft);
|
|
||||||
p_tv->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
|
|
||||||
p_tv->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Always return 0 as per Open Group Base Specifications Issue 6.
|
|
||||||
Do not set errno on error. */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,27 +0,0 @@
|
||||||
//
|
|
||||||
// Systime.h
|
|
||||||
// libraries/shared/src
|
|
||||||
//
|
|
||||||
// Copyright 2013 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_Systime_h
|
|
||||||
#define hifi_Systime_h
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
|
|
||||||
#include <winsock2.h>
|
|
||||||
|
|
||||||
struct timezone {
|
|
||||||
int tz_minuteswest; /* minutes west of Greenwich */
|
|
||||||
int tz_dsttime; /* type of dst correction */
|
|
||||||
};
|
|
||||||
|
|
||||||
int gettimeofday(struct timeval* p_tv, struct timezone* p_tz);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // hifi_Systime_h
|
|
|
@ -42,7 +42,11 @@ void VoxelTree::deleteVoxelAt(float x, float y, float z, float s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelTreeElement* VoxelTree::getVoxelAt(float x, float y, float z, float s) const {
|
VoxelTreeElement* VoxelTree::getVoxelAt(float x, float y, float z, float s) const {
|
||||||
return (VoxelTreeElement*)getOctreeElementAt(x, y, z, s);
|
return static_cast<VoxelTreeElement*>(getOctreeElementAt(x, y, z, s));
|
||||||
|
}
|
||||||
|
|
||||||
|
VoxelTreeElement* VoxelTree::getEnclosingVoxelAt(float x, float y, float z, float s) const {
|
||||||
|
return static_cast<VoxelTreeElement*>(getOctreeEnclosingElementAt(x, y, z, s));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelTree::createVoxel(float x, float y, float z, float s,
|
void VoxelTree::createVoxel(float x, float y, float z, float s,
|
||||||
|
|
|
@ -29,7 +29,15 @@ public:
|
||||||
VoxelTreeElement* getRoot() { return (VoxelTreeElement*)_rootNode; }
|
VoxelTreeElement* getRoot() { return (VoxelTreeElement*)_rootNode; }
|
||||||
|
|
||||||
void deleteVoxelAt(float x, float y, float z, float s);
|
void deleteVoxelAt(float x, float y, float z, float s);
|
||||||
|
|
||||||
|
/// Find the voxel at position x,y,z,s
|
||||||
|
/// \return pointer to the VoxelTreeElement or NULL if none at x,y,z,s.
|
||||||
VoxelTreeElement* getVoxelAt(float x, float y, float z, float s) const;
|
VoxelTreeElement* getVoxelAt(float x, float y, float z, float s) const;
|
||||||
|
|
||||||
|
/// Find the voxel at position x,y,z,s
|
||||||
|
/// \return pointer to the VoxelTreeElement or to the smallest enclosing parent if none at x,y,z,s.
|
||||||
|
VoxelTreeElement* getEnclosingVoxelAt(float x, float y, float z, float s) const;
|
||||||
|
|
||||||
void createVoxel(float x, float y, float z, float s,
|
void createVoxel(float x, float y, float z, float s,
|
||||||
unsigned char red, unsigned char green, unsigned char blue, bool destructive = false);
|
unsigned char red, unsigned char green, unsigned char blue, bool destructive = false);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,50 @@
|
||||||
|
|
||||||
#include "VoxelTreeCommands.h"
|
#include "VoxelTreeCommands.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct SendVoxelsOperationArgs {
|
||||||
|
const unsigned char* newBaseOctCode;
|
||||||
|
VoxelEditPacketSender* packetSender;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool sendVoxelsOperation(OctreeElement* element, void* extraData) {
|
||||||
|
VoxelTreeElement* voxel = static_cast<VoxelTreeElement*>(element);
|
||||||
|
SendVoxelsOperationArgs* args = static_cast<SendVoxelsOperationArgs*>(extraData);
|
||||||
|
if (voxel->isColored()) {
|
||||||
|
const unsigned char* nodeOctalCode = voxel->getOctalCode();
|
||||||
|
unsigned char* codeColorBuffer = NULL;
|
||||||
|
int codeLength = 0;
|
||||||
|
int bytesInCode = 0;
|
||||||
|
int codeAndColorLength;
|
||||||
|
|
||||||
|
// If the newBase is NULL, then don't rebase
|
||||||
|
if (args->newBaseOctCode) {
|
||||||
|
codeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true);
|
||||||
|
codeLength = numberOfThreeBitSectionsInCode(codeColorBuffer);
|
||||||
|
bytesInCode = bytesRequiredForCodeLength(codeLength);
|
||||||
|
codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA;
|
||||||
|
} else {
|
||||||
|
codeLength = numberOfThreeBitSectionsInCode(nodeOctalCode);
|
||||||
|
bytesInCode = bytesRequiredForCodeLength(codeLength);
|
||||||
|
codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA;
|
||||||
|
codeColorBuffer = new unsigned char[codeAndColorLength];
|
||||||
|
memcpy(codeColorBuffer, nodeOctalCode, bytesInCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the colors over
|
||||||
|
codeColorBuffer[bytesInCode + RED_INDEX] = voxel->getColor()[RED_INDEX];
|
||||||
|
codeColorBuffer[bytesInCode + GREEN_INDEX] = voxel->getColor()[GREEN_INDEX];
|
||||||
|
codeColorBuffer[bytesInCode + BLUE_INDEX] = voxel->getColor()[BLUE_INDEX];
|
||||||
|
args->packetSender->queueVoxelEditMessage(PacketTypeVoxelSetDestructive,
|
||||||
|
codeColorBuffer, codeAndColorLength);
|
||||||
|
|
||||||
|
delete[] codeColorBuffer;
|
||||||
|
}
|
||||||
|
return true; // keep going
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
AddVoxelCommand::AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) :
|
AddVoxelCommand::AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) :
|
||||||
QUndoCommand("Add Voxel", parent),
|
QUndoCommand("Add Voxel", parent),
|
||||||
_tree(tree),
|
_tree(tree),
|
||||||
|
@ -43,11 +87,40 @@ DeleteVoxelCommand::DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, Voxe
|
||||||
QUndoCommand("Delete Voxel", parent),
|
QUndoCommand("Delete Voxel", parent),
|
||||||
_tree(tree),
|
_tree(tree),
|
||||||
_packetSender(packetSender),
|
_packetSender(packetSender),
|
||||||
_voxel(voxel)
|
_voxel(voxel),
|
||||||
|
_oldTree(NULL)
|
||||||
{
|
{
|
||||||
|
_tree->lockForRead();
|
||||||
|
VoxelTreeElement* element = _tree->getEnclosingVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s);
|
||||||
|
if (element->getScale() == _voxel.s) {
|
||||||
|
if (!element->hasContent() && !element->isLeaf()) {
|
||||||
|
_oldTree = new VoxelTree();
|
||||||
|
_tree->copySubTreeIntoNewTree(element, _oldTree, false);
|
||||||
|
} else {
|
||||||
|
_voxel.red = element->getColor()[0];
|
||||||
|
_voxel.green = element->getColor()[1];
|
||||||
|
_voxel.blue = element->getColor()[2];
|
||||||
|
}
|
||||||
|
} else if (element->hasContent() && element->isLeaf()) {
|
||||||
|
_voxel.red = element->getColor()[0];
|
||||||
|
_voxel.green = element->getColor()[1];
|
||||||
|
_voxel.blue = element->getColor()[2];
|
||||||
|
} else {
|
||||||
|
_voxel.s = 0.0f;
|
||||||
|
qDebug() << "No element for delete.";
|
||||||
|
}
|
||||||
|
_tree->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteVoxelCommand::~DeleteVoxelCommand() {
|
||||||
|
delete _oldTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteVoxelCommand::redo() {
|
void DeleteVoxelCommand::redo() {
|
||||||
|
if (_voxel.s == 0.0f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_tree) {
|
if (_tree) {
|
||||||
_tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s);
|
_tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s);
|
||||||
}
|
}
|
||||||
|
@ -57,10 +130,32 @@ void DeleteVoxelCommand::redo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteVoxelCommand::undo() {
|
void DeleteVoxelCommand::undo() {
|
||||||
if (_tree) {
|
if (_voxel.s == 0.0f) {
|
||||||
_tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue);
|
return;
|
||||||
}
|
}
|
||||||
if (_packetSender) {
|
|
||||||
_packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel);
|
if (_oldTree) {
|
||||||
|
VoxelTreeElement* element = _oldTree->getVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s);
|
||||||
|
if (element) {
|
||||||
|
if (_tree) {
|
||||||
|
_tree->lockForWrite();
|
||||||
|
_oldTree->copySubTreeIntoNewTree(element, _tree, false);
|
||||||
|
_tree->unlock();
|
||||||
|
}
|
||||||
|
if (_packetSender) {
|
||||||
|
SendVoxelsOperationArgs args;
|
||||||
|
args.newBaseOctCode = NULL;
|
||||||
|
args.packetSender = _packetSender;
|
||||||
|
_oldTree->recurseTreeWithOperation(sendVoxelsOperation, &args);
|
||||||
|
_packetSender->releaseQueuedMessages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_tree) {
|
||||||
|
_tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue);
|
||||||
|
}
|
||||||
|
if (_packetSender) {
|
||||||
|
_packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ private:
|
||||||
class DeleteVoxelCommand : public QUndoCommand {
|
class DeleteVoxelCommand : public QUndoCommand {
|
||||||
public:
|
public:
|
||||||
DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL);
|
DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL);
|
||||||
|
~DeleteVoxelCommand();
|
||||||
|
|
||||||
virtual void redo();
|
virtual void redo();
|
||||||
virtual void undo();
|
virtual void undo();
|
||||||
|
@ -44,6 +45,7 @@ private:
|
||||||
VoxelTree* _tree;
|
VoxelTree* _tree;
|
||||||
VoxelEditPacketSender* _packetSender;
|
VoxelEditPacketSender* _packetSender;
|
||||||
VoxelDetail _voxel;
|
VoxelDetail _voxel;
|
||||||
|
VoxelTree* _oldTree;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_VoxelTreeCommands_h
|
#endif // hifi_VoxelTreeCommands_h
|
||||||
|
|
|
@ -76,32 +76,16 @@ void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale,
|
||||||
if (_tree) {
|
if (_tree) {
|
||||||
if (_undoStack) {
|
if (_undoStack) {
|
||||||
AddVoxelCommand* addCommand = new AddVoxelCommand(_tree,
|
AddVoxelCommand* addCommand = new AddVoxelCommand(_tree,
|
||||||
addVoxelDetail,
|
addVoxelDetail,
|
||||||
getVoxelPacketSender());
|
getVoxelPacketSender());
|
||||||
|
DeleteVoxelCommand* deleteCommand = new DeleteVoxelCommand(_tree,
|
||||||
VoxelTreeElement* deleteVoxelElement = _tree->getVoxelAt(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s);
|
addVoxelDetail,
|
||||||
if (deleteVoxelElement) {
|
getVoxelPacketSender());
|
||||||
nodeColor color;
|
_undoStack->beginMacro(addCommand->text());
|
||||||
memcpy(&color, &deleteVoxelElement->getColor(), sizeof(nodeColor));
|
// As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves.
|
||||||
VoxelDetail deleteVoxelDetail = {addVoxelDetail.x,
|
_undoStack->push(deleteCommand);
|
||||||
addVoxelDetail.y,
|
_undoStack->push(addCommand);
|
||||||
addVoxelDetail.z,
|
_undoStack->endMacro();
|
||||||
addVoxelDetail.s,
|
|
||||||
color[0],
|
|
||||||
color[1],
|
|
||||||
color[2]};
|
|
||||||
DeleteVoxelCommand* delCommand = new DeleteVoxelCommand(_tree,
|
|
||||||
deleteVoxelDetail,
|
|
||||||
getVoxelPacketSender());
|
|
||||||
_undoStack->beginMacro(addCommand->text());
|
|
||||||
// As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves.
|
|
||||||
_undoStack->push(delCommand);
|
|
||||||
_undoStack->push(addCommand);
|
|
||||||
_undoStack->endMacro();
|
|
||||||
} else {
|
|
||||||
// As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves.
|
|
||||||
_undoStack->push(addCommand);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// queue the destructive add
|
// queue the destructive add
|
||||||
queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail);
|
queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail);
|
||||||
|
|
Loading…
Reference in a new issue