mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 16:14:45 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into raypick-avatars
This commit is contained in:
commit
6786a07ac2
23 changed files with 844 additions and 144 deletions
BIN
interface/resources/images/preview.png
Normal file
BIN
interface/resources/images/preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
|
@ -3049,17 +3049,20 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::exportEntities(const QString& filename, float x, float y, float z, float scale) {
|
bool Application::exportEntities(const QString& filename, float x, float y, float z, float scale) {
|
||||||
glm::vec3 offset(x, y, z);
|
glm::vec3 center(x, y, z);
|
||||||
|
glm::vec3 minCorner = center - vec3(scale);
|
||||||
|
float cubeSize = scale * 2;
|
||||||
|
AACube boundingCube(minCorner, cubeSize);
|
||||||
QVector<EntityItemPointer> entities;
|
QVector<EntityItemPointer> entities;
|
||||||
QVector<EntityItemID> ids;
|
QVector<EntityItemID> ids;
|
||||||
auto entityTree = getEntities()->getTree();
|
auto entityTree = getEntities()->getTree();
|
||||||
entityTree->withReadLock([&] {
|
entityTree->withReadLock([&] {
|
||||||
entityTree->findEntities(AACube(offset, scale), entities);
|
entityTree->findEntities(boundingCube, entities);
|
||||||
foreach(EntityItemPointer entity, entities) {
|
foreach(EntityItemPointer entity, entities) {
|
||||||
ids << entity->getEntityItemID();
|
ids << entity->getEntityItemID();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return exportEntities(filename, ids, &offset);
|
return exportEntities(filename, ids, ¢er);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::loadSettings() {
|
void Application::loadSettings() {
|
||||||
|
|
|
@ -45,7 +45,7 @@ void ModelOverlay::update(float deltatime) {
|
||||||
_updateModel = false;
|
_updateModel = false;
|
||||||
|
|
||||||
_model->setSnapModelToCenter(true);
|
_model->setSnapModelToCenter(true);
|
||||||
_model->setScale(getDimensions());
|
_model->setScaleToFit(true, getDimensions());
|
||||||
_model->setRotation(getRotation());
|
_model->setRotation(getRotation());
|
||||||
_model->setTranslation(getPosition());
|
_model->setTranslation(getPosition());
|
||||||
_model->setURL(_url);
|
_model->setURL(_url);
|
||||||
|
@ -100,7 +100,6 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
|
||||||
if (newScale.x <= 0 || newScale.y <= 0 || newScale.z <= 0) {
|
if (newScale.x <= 0 || newScale.y <= 0 || newScale.z <= 0) {
|
||||||
setDimensions(scale);
|
setDimensions(scale);
|
||||||
} else {
|
} else {
|
||||||
_model->setScaleToFit(true, getDimensions());
|
|
||||||
_updateModel = true;
|
_updateModel = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
#include "AudioReverb.h"
|
#include "AudioReverb.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable : 4351) // new behavior: elements of array will be default initialized
|
|
||||||
|
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
inline static int MULHI(int a, int b) {
|
inline static int MULHI(int a, int b) {
|
||||||
long long c = __emul(a, b);
|
long long c = __emul(a, b);
|
||||||
return ((int*)&c)[1];
|
return ((int*)&c)[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define MULHI(a,b) (int)(((long long)(a) * (b)) >> 32)
|
#define MULHI(a,b) (int)(((long long)(a) * (b)) >> 32)
|
||||||
|
@ -1725,7 +1725,7 @@ void ReverbImpl::reset() {
|
||||||
// Public API
|
// Public API
|
||||||
//
|
//
|
||||||
|
|
||||||
static const int REVERB_BLOCK = 1024;
|
static const int REVERB_BLOCK = 256;
|
||||||
|
|
||||||
AudioReverb::AudioReverb(float sampleRate) {
|
AudioReverb::AudioReverb(float sampleRate) {
|
||||||
|
|
||||||
|
@ -1804,7 +1804,7 @@ void AudioReverb::render(float** inputs, float** outputs, int numFrames) {
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
|
||||||
// convert int16_t to float, deinterleave stereo
|
// convert int16_t to float, deinterleave stereo
|
||||||
void AudioReverb::convertInputFromInt16(const int16_t* input, float** outputs, int numFrames) {
|
void AudioReverb::convertInput(const int16_t* input, float** outputs, int numFrames) {
|
||||||
__m128 scale = _mm_set1_ps(1/32768.0f);
|
__m128 scale = _mm_set1_ps(1/32768.0f);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -1855,8 +1855,8 @@ static inline __m128 dither4() {
|
||||||
return _mm_mul_ps(d0, _mm_set1_ps(1/65536.0f));
|
return _mm_mul_ps(d0, _mm_set1_ps(1/65536.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert float to int16_t, interleave stereo
|
// convert float to int16_t with dither, interleave stereo
|
||||||
void AudioReverb::convertOutputToInt16(float** inputs, int16_t* output, int numFrames) {
|
void AudioReverb::convertOutput(float** inputs, int16_t* output, int numFrames) {
|
||||||
__m128 scale = _mm_set1_ps(32768.0f);
|
__m128 scale = _mm_set1_ps(32768.0f);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -1898,10 +1898,48 @@ void AudioReverb::convertOutputToInt16(float** inputs, int16_t* output, int numF
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deinterleave stereo
|
||||||
|
void AudioReverb::convertInput(const float* input, float** outputs, int numFrames) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (; i < numFrames - 3; i += 4) {
|
||||||
|
__m128 f0 = _mm_loadu_ps(&input[2*i + 0]);
|
||||||
|
__m128 f1 = _mm_loadu_ps(&input[2*i + 4]);
|
||||||
|
|
||||||
|
// deinterleave
|
||||||
|
_mm_storeu_ps(&outputs[0][i], _mm_shuffle_ps(f0, f1, _MM_SHUFFLE(2,0,2,0)));
|
||||||
|
_mm_storeu_ps(&outputs[1][i], _mm_shuffle_ps(f0, f1, _MM_SHUFFLE(3,1,3,1)));
|
||||||
|
}
|
||||||
|
for (; i < numFrames; i++) {
|
||||||
|
// deinterleave
|
||||||
|
outputs[0][i] = input[2*i + 0];
|
||||||
|
outputs[1][i] = input[2*i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// interleave stereo
|
||||||
|
void AudioReverb::convertOutput(float** inputs, float* output, int numFrames) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for(; i < numFrames - 3; i += 4) {
|
||||||
|
__m128 f0 = _mm_loadu_ps(&inputs[0][i]);
|
||||||
|
__m128 f1 = _mm_loadu_ps(&inputs[1][i]);
|
||||||
|
|
||||||
|
// interleave
|
||||||
|
_mm_storeu_ps(&output[2*i + 0],_mm_unpacklo_ps(f0,f1));
|
||||||
|
_mm_storeu_ps(&output[2*i + 4],_mm_unpackhi_ps(f0,f1));
|
||||||
|
}
|
||||||
|
for(; i < numFrames; i++) {
|
||||||
|
// interleave
|
||||||
|
output[2*i + 0] = inputs[0][i];
|
||||||
|
output[2*i + 1] = inputs[1][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// convert int16_t to float, deinterleave stereo
|
// convert int16_t to float, deinterleave stereo
|
||||||
void AudioReverb::convertInputFromInt16(const int16_t* input, float** outputs, int numFrames) {
|
void AudioReverb::convertInput(const int16_t* input, float** outputs, int numFrames) {
|
||||||
const float scale = 1/32768.0f;
|
const float scale = 1/32768.0f;
|
||||||
|
|
||||||
for (int i = 0; i < numFrames; i++) {
|
for (int i = 0; i < numFrames; i++) {
|
||||||
|
@ -1919,8 +1957,8 @@ static inline float dither() {
|
||||||
return (int32_t)(r0 - r1) * (1/65536.0f);
|
return (int32_t)(r0 - r1) * (1/65536.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert float to int16_t, interleave stereo
|
// convert float to int16_t with dither, interleave stereo
|
||||||
void AudioReverb::convertOutputToInt16(float** inputs, int16_t* output, int numFrames) {
|
void AudioReverb::convertOutput(float** inputs, int16_t* output, int numFrames) {
|
||||||
const float scale = 32768.0f;
|
const float scale = 32768.0f;
|
||||||
|
|
||||||
for (int i = 0; i < numFrames; i++) {
|
for (int i = 0; i < numFrames; i++) {
|
||||||
|
@ -1944,6 +1982,26 @@ void AudioReverb::convertOutputToInt16(float** inputs, int16_t* output, int numF
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deinterleave stereo
|
||||||
|
void AudioReverb::convertInput(const float* input, float** outputs, int numFrames) {
|
||||||
|
|
||||||
|
for (int i = 0; i < numFrames; i++) {
|
||||||
|
// deinterleave
|
||||||
|
outputs[0][i] = input[2*i + 0];
|
||||||
|
outputs[1][i] = input[2*i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// interleave stereo
|
||||||
|
void AudioReverb::convertOutput(float** inputs, float* output, int numFrames) {
|
||||||
|
|
||||||
|
for (int i = 0; i < numFrames; i++) {
|
||||||
|
// interleave
|
||||||
|
output[2*i + 0] = inputs[0][i];
|
||||||
|
output[2*i + 1] = inputs[1][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1955,11 +2013,32 @@ void AudioReverb::render(const int16_t* input, int16_t* output, int numFrames) {
|
||||||
|
|
||||||
int n = MIN(numFrames, REVERB_BLOCK);
|
int n = MIN(numFrames, REVERB_BLOCK);
|
||||||
|
|
||||||
convertInputFromInt16(input, _inout, n);
|
convertInput(input, _inout, n);
|
||||||
|
|
||||||
_impl->process(_inout, _inout, n);
|
_impl->process(_inout, _inout, n);
|
||||||
|
|
||||||
convertOutputToInt16(_inout, output, n);
|
convertOutput(_inout, output, n);
|
||||||
|
|
||||||
|
input += 2 * n;
|
||||||
|
output += 2 * n;
|
||||||
|
numFrames -= n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// This version handles input/output as interleaved float
|
||||||
|
//
|
||||||
|
void AudioReverb::render(const float* input, float* output, int numFrames) {
|
||||||
|
|
||||||
|
while (numFrames) {
|
||||||
|
|
||||||
|
int n = MIN(numFrames, REVERB_BLOCK);
|
||||||
|
|
||||||
|
convertInput(input, _inout, n);
|
||||||
|
|
||||||
|
_impl->process(_inout, _inout, n);
|
||||||
|
|
||||||
|
convertOutput(_inout, output, n);
|
||||||
|
|
||||||
input += 2 * n;
|
input += 2 * n;
|
||||||
output += 2 * n;
|
output += 2 * n;
|
||||||
|
|
|
@ -64,13 +64,20 @@ public:
|
||||||
// interleaved int16_t input/output
|
// interleaved int16_t input/output
|
||||||
void render(const int16_t* input, int16_t* output, int numFrames);
|
void render(const int16_t* input, int16_t* output, int numFrames);
|
||||||
|
|
||||||
|
// interleaved float input/output
|
||||||
|
void render(const float* input, float* output, int numFrames);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReverbImpl *_impl;
|
ReverbImpl *_impl;
|
||||||
ReverbParameters _params;
|
ReverbParameters _params;
|
||||||
|
|
||||||
float* _inout[2];
|
float* _inout[2];
|
||||||
void convertInputFromInt16(const int16_t* input, float** outputs, int numFrames);
|
|
||||||
void convertOutputToInt16(float** inputs, int16_t* output, int numFrames);
|
void convertInput(const int16_t* input, float** outputs, int numFrames);
|
||||||
|
void convertOutput(float** inputs, int16_t* output, int numFrames);
|
||||||
|
|
||||||
|
void convertInput(const float* input, float** outputs, int numFrames);
|
||||||
|
void convertOutput(float** inputs, float* output, int numFrames);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AudioReverb_h
|
#endif // hifi_AudioReverb_h
|
||||||
|
|
|
@ -389,7 +389,7 @@ int AudioSRC::multirateFilter2(const float* input0, const float* input1, float*
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert int16_t to float, deinterleave stereo
|
// convert int16_t to float, deinterleave stereo
|
||||||
void AudioSRC::convertInputFromInt16(const int16_t* input, float** outputs, int numFrames) {
|
void AudioSRC::convertInput(const int16_t* input, float** outputs, int numFrames) {
|
||||||
__m128 scale = _mm_set1_ps(1/32768.0f);
|
__m128 scale = _mm_set1_ps(1/32768.0f);
|
||||||
|
|
||||||
if (_numChannels == 1) {
|
if (_numChannels == 1) {
|
||||||
|
@ -467,8 +467,8 @@ static inline __m128 dither4() {
|
||||||
return _mm_mul_ps(d0, _mm_set1_ps(1/65536.0f));
|
return _mm_mul_ps(d0, _mm_set1_ps(1/65536.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert float to int16_t, interleave stereo
|
// convert float to int16_t with dither, interleave stereo
|
||||||
void AudioSRC::convertOutputToInt16(float** inputs, int16_t* output, int numFrames) {
|
void AudioSRC::convertOutput(float** inputs, int16_t* output, int numFrames) {
|
||||||
__m128 scale = _mm_set1_ps(32768.0f);
|
__m128 scale = _mm_set1_ps(32768.0f);
|
||||||
|
|
||||||
if (_numChannels == 1) {
|
if (_numChannels == 1) {
|
||||||
|
@ -539,6 +539,58 @@ void AudioSRC::convertOutputToInt16(float** inputs, int16_t* output, int numFram
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deinterleave stereo
|
||||||
|
void AudioSRC::convertInput(const float* input, float** outputs, int numFrames) {
|
||||||
|
|
||||||
|
if (_numChannels == 1) {
|
||||||
|
|
||||||
|
memcpy(outputs[0], input, numFrames * sizeof(float));
|
||||||
|
|
||||||
|
} else if (_numChannels == 2) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (; i < numFrames - 3; i += 4) {
|
||||||
|
__m128 f0 = _mm_loadu_ps(&input[2*i + 0]);
|
||||||
|
__m128 f1 = _mm_loadu_ps(&input[2*i + 4]);
|
||||||
|
|
||||||
|
// deinterleave
|
||||||
|
_mm_storeu_ps(&outputs[0][i], _mm_shuffle_ps(f0, f1, _MM_SHUFFLE(2,0,2,0)));
|
||||||
|
_mm_storeu_ps(&outputs[1][i], _mm_shuffle_ps(f0, f1, _MM_SHUFFLE(3,1,3,1)));
|
||||||
|
}
|
||||||
|
for (; i < numFrames; i++) {
|
||||||
|
// deinterleave
|
||||||
|
outputs[0][i] = input[2*i + 0];
|
||||||
|
outputs[1][i] = input[2*i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// interleave stereo
|
||||||
|
void AudioSRC::convertOutput(float** inputs, float* output, int numFrames) {
|
||||||
|
|
||||||
|
if (_numChannels == 1) {
|
||||||
|
|
||||||
|
memcpy(output, inputs[0], numFrames * sizeof(float));
|
||||||
|
|
||||||
|
} else if (_numChannels == 2) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (; i < numFrames - 3; i += 4) {
|
||||||
|
__m128 f0 = _mm_loadu_ps(&inputs[0][i]);
|
||||||
|
__m128 f1 = _mm_loadu_ps(&inputs[1][i]);
|
||||||
|
|
||||||
|
// interleave
|
||||||
|
_mm_storeu_ps(&output[2*i + 0], _mm_unpacklo_ps(f0, f1));
|
||||||
|
_mm_storeu_ps(&output[2*i + 4], _mm_unpackhi_ps(f0, f1));
|
||||||
|
}
|
||||||
|
for (; i < numFrames; i++) {
|
||||||
|
// interleave
|
||||||
|
output[2*i + 0] = inputs[0][i];
|
||||||
|
output[2*i + 1] = inputs[1][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
int AudioSRC::multirateFilter1(const float* input0, float* output0, int inputFrames) {
|
int AudioSRC::multirateFilter1(const float* input0, float* output0, int inputFrames) {
|
||||||
|
@ -674,7 +726,7 @@ int AudioSRC::multirateFilter2(const float* input0, const float* input1, float*
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert int16_t to float, deinterleave stereo
|
// convert int16_t to float, deinterleave stereo
|
||||||
void AudioSRC::convertInputFromInt16(const int16_t* input, float** outputs, int numFrames) {
|
void AudioSRC::convertInput(const int16_t* input, float** outputs, int numFrames) {
|
||||||
const float scale = 1/32768.0f;
|
const float scale = 1/32768.0f;
|
||||||
|
|
||||||
if (_numChannels == 1) {
|
if (_numChannels == 1) {
|
||||||
|
@ -698,8 +750,8 @@ static inline float dither() {
|
||||||
return (int32_t)(r0 - r1) * (1/65536.0f);
|
return (int32_t)(r0 - r1) * (1/65536.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert float to int16_t, interleave stereo
|
// convert float to int16_t with dither, interleave stereo
|
||||||
void AudioSRC::convertOutputToInt16(float** inputs, int16_t* output, int numFrames) {
|
void AudioSRC::convertOutput(float** inputs, int16_t* output, int numFrames) {
|
||||||
const float scale = 32768.0f;
|
const float scale = 32768.0f;
|
||||||
|
|
||||||
if (_numChannels == 1) {
|
if (_numChannels == 1) {
|
||||||
|
@ -738,9 +790,41 @@ void AudioSRC::convertOutputToInt16(float** inputs, int16_t* output, int numFram
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deinterleave stereo
|
||||||
|
void AudioSRC::convertInput(const float* input, float** outputs, int numFrames) {
|
||||||
|
|
||||||
|
if (_numChannels == 1) {
|
||||||
|
|
||||||
|
memcpy(outputs[0], input, numFrames * sizeof(float));
|
||||||
|
|
||||||
|
} else if (_numChannels == 2) {
|
||||||
|
for (int i = 0; i < numFrames; i++) {
|
||||||
|
// deinterleave
|
||||||
|
outputs[0][i] = input[2*i + 0];
|
||||||
|
outputs[1][i] = input[2*i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// interleave stereo
|
||||||
|
void AudioSRC::convertOutput(float** inputs, float* output, int numFrames) {
|
||||||
|
|
||||||
|
if (_numChannels == 1) {
|
||||||
|
|
||||||
|
memcpy(output, inputs[0], numFrames * sizeof(float));
|
||||||
|
|
||||||
|
} else if (_numChannels == 2) {
|
||||||
|
for (int i = 0; i < numFrames; i++) {
|
||||||
|
// interleave
|
||||||
|
output[2*i + 0] = inputs[0][i];
|
||||||
|
output[2*i + 1] = inputs[1][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int AudioSRC::processFloat(float** inputs, float** outputs, int inputFrames) {
|
int AudioSRC::render(float** inputs, float** outputs, int inputFrames) {
|
||||||
int outputFrames = 0;
|
int outputFrames = 0;
|
||||||
|
|
||||||
int nh = std::min(_numHistory, inputFrames); // number of frames from history buffer
|
int nh = std::min(_numHistory, inputFrames); // number of frames from history buffer
|
||||||
|
@ -749,19 +833,19 @@ int AudioSRC::processFloat(float** inputs, float** outputs, int inputFrames) {
|
||||||
if (_numChannels == 1) {
|
if (_numChannels == 1) {
|
||||||
|
|
||||||
// refill history buffers
|
// refill history buffers
|
||||||
memcpy(_history[0] + _numHistory, _inputs[0], nh * sizeof(float));
|
memcpy(_history[0] + _numHistory, inputs[0], nh * sizeof(float));
|
||||||
|
|
||||||
// process history buffer
|
// process history buffer
|
||||||
outputFrames += multirateFilter1(_history[0], _outputs[0], nh);
|
outputFrames += multirateFilter1(_history[0], outputs[0], nh);
|
||||||
|
|
||||||
// process remaining input
|
// process remaining input
|
||||||
if (ni) {
|
if (ni) {
|
||||||
outputFrames += multirateFilter1(_inputs[0], _outputs[0] + outputFrames, ni);
|
outputFrames += multirateFilter1(inputs[0], outputs[0] + outputFrames, ni);
|
||||||
}
|
}
|
||||||
|
|
||||||
// shift history buffers
|
// shift history buffers
|
||||||
if (ni) {
|
if (ni) {
|
||||||
memcpy(_history[0], _inputs[0] + ni, _numHistory * sizeof(float));
|
memcpy(_history[0], inputs[0] + ni, _numHistory * sizeof(float));
|
||||||
} else {
|
} else {
|
||||||
memmove(_history[0], _history[0] + nh, _numHistory * sizeof(float));
|
memmove(_history[0], _history[0] + nh, _numHistory * sizeof(float));
|
||||||
}
|
}
|
||||||
|
@ -769,15 +853,15 @@ int AudioSRC::processFloat(float** inputs, float** outputs, int inputFrames) {
|
||||||
} else if (_numChannels == 2) {
|
} else if (_numChannels == 2) {
|
||||||
|
|
||||||
// refill history buffers
|
// refill history buffers
|
||||||
memcpy(_history[0] + _numHistory, _inputs[0], nh * sizeof(float));
|
memcpy(_history[0] + _numHistory, inputs[0], nh * sizeof(float));
|
||||||
memcpy(_history[1] + _numHistory, _inputs[1], nh * sizeof(float));
|
memcpy(_history[1] + _numHistory, inputs[1], nh * sizeof(float));
|
||||||
|
|
||||||
// process history buffer
|
// process history buffer
|
||||||
outputFrames += multirateFilter2(_history[0], _history[1], _outputs[0], _outputs[1], nh);
|
outputFrames += multirateFilter2(_history[0], _history[1], outputs[0], outputs[1], nh);
|
||||||
|
|
||||||
// process remaining input
|
// process remaining input
|
||||||
if (ni) {
|
if (ni) {
|
||||||
outputFrames += multirateFilter2(_inputs[0], _inputs[1], _outputs[0] + outputFrames, _outputs[1] + outputFrames, ni);
|
outputFrames += multirateFilter2(inputs[0], inputs[1], outputs[0] + outputFrames, outputs[1] + outputFrames, ni);
|
||||||
}
|
}
|
||||||
|
|
||||||
// shift history buffers
|
// shift history buffers
|
||||||
|
@ -869,12 +953,38 @@ int AudioSRC::render(const int16_t* input, int16_t* output, int inputFrames) {
|
||||||
|
|
||||||
int ni = std::min(inputFrames, _inputBlock);
|
int ni = std::min(inputFrames, _inputBlock);
|
||||||
|
|
||||||
convertInputFromInt16(input, _inputs, ni);
|
convertInput(input, _inputs, ni);
|
||||||
|
|
||||||
int no = processFloat(_inputs, _outputs, ni);
|
int no = render(_inputs, _outputs, ni);
|
||||||
assert(no <= SRC_BLOCK);
|
assert(no <= SRC_BLOCK);
|
||||||
|
|
||||||
convertOutputToInt16(_outputs, output, no);
|
convertOutput(_outputs, output, no);
|
||||||
|
|
||||||
|
input += _numChannels * ni;
|
||||||
|
output += _numChannels * no;
|
||||||
|
inputFrames -= ni;
|
||||||
|
outputFrames += no;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// This version handles input/output as interleaved float
|
||||||
|
//
|
||||||
|
int AudioSRC::render(const float* input, float* output, int inputFrames) {
|
||||||
|
int outputFrames = 0;
|
||||||
|
|
||||||
|
while (inputFrames) {
|
||||||
|
|
||||||
|
int ni = std::min(inputFrames, _inputBlock);
|
||||||
|
|
||||||
|
convertInput(input, _inputs, ni);
|
||||||
|
|
||||||
|
int no = render(_inputs, _outputs, ni);
|
||||||
|
assert(no <= SRC_BLOCK);
|
||||||
|
|
||||||
|
convertOutput(_outputs, output, no);
|
||||||
|
|
||||||
input += _numChannels * ni;
|
input += _numChannels * ni;
|
||||||
output += _numChannels * no;
|
output += _numChannels * no;
|
||||||
|
|
|
@ -34,8 +34,15 @@ public:
|
||||||
AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels);
|
AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels);
|
||||||
~AudioSRC();
|
~AudioSRC();
|
||||||
|
|
||||||
|
// deinterleaved float input/output (native format)
|
||||||
|
int render(float** inputs, float** outputs, int inputFrames);
|
||||||
|
|
||||||
|
// interleaved int16_t input/output
|
||||||
int render(const int16_t* input, int16_t* output, int inputFrames);
|
int render(const int16_t* input, int16_t* output, int inputFrames);
|
||||||
|
|
||||||
|
// interleaved float input/output
|
||||||
|
int render(const float* input, float* output, int inputFrames);
|
||||||
|
|
||||||
int getMinOutput(int inputFrames);
|
int getMinOutput(int inputFrames);
|
||||||
int getMaxOutput(int inputFrames);
|
int getMaxOutput(int inputFrames);
|
||||||
int getMinInput(int outputFrames);
|
int getMinInput(int outputFrames);
|
||||||
|
@ -75,10 +82,11 @@ private:
|
||||||
int multirateFilter1_AVX2(const float* input0, float* output0, int inputFrames);
|
int multirateFilter1_AVX2(const float* input0, float* output0, int inputFrames);
|
||||||
int multirateFilter2_AVX2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
|
int multirateFilter2_AVX2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
|
||||||
|
|
||||||
void convertInputFromInt16(const int16_t* input, float** outputs, int numFrames);
|
void convertInput(const int16_t* input, float** outputs, int numFrames);
|
||||||
void convertOutputToInt16(float** inputs, int16_t* output, int numFrames);
|
void convertOutput(float** inputs, int16_t* output, int numFrames);
|
||||||
|
|
||||||
int processFloat(float** inputs, float** outputs, int inputFrames);
|
void convertInput(const float* input, float** outputs, int numFrames);
|
||||||
|
void convertOutput(float** inputs, float* output, int numFrames);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AudioSRC_h
|
#endif // AudioSRC_h
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
#include <QtOpenGL/QGLWidget>
|
#include <QtOpenGL/QGLWidget>
|
||||||
#include <QtGui/QImage>
|
#include <QtGui/QImage>
|
||||||
|
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
#include <OpenGL/CGLCurrent.h>
|
||||||
|
#endif
|
||||||
#include <gl/QOpenGLContextWrapper.h>
|
#include <gl/QOpenGLContextWrapper.h>
|
||||||
#include <gpu/Texture.h>
|
#include <gpu/Texture.h>
|
||||||
#include <gl/GLWidget.h>
|
#include <gl/GLWidget.h>
|
||||||
|
@ -612,8 +615,14 @@ void OpenGLDisplayPlugin::enableVsync(bool enable) {
|
||||||
if (!_vsyncSupported) {
|
if (!_vsyncSupported) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef Q_OS_WIN
|
#if defined(Q_OS_WIN)
|
||||||
wglSwapIntervalEXT(enable ? 1 : 0);
|
wglSwapIntervalEXT(enable ? 1 : 0);
|
||||||
|
#elif defined(Q_OS_MAC)
|
||||||
|
GLint interval = enable ? 1 : 0;
|
||||||
|
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
|
||||||
|
#else
|
||||||
|
// TODO: Fill in for linux
|
||||||
|
return;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,9 +630,14 @@ bool OpenGLDisplayPlugin::isVsyncEnabled() {
|
||||||
if (!_vsyncSupported) {
|
if (!_vsyncSupported) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#ifdef Q_OS_WIN
|
#if defined(Q_OS_WIN)
|
||||||
return wglGetSwapIntervalEXT() != 0;
|
return wglGetSwapIntervalEXT() != 0;
|
||||||
|
#elif defined(Q_OS_MAC)
|
||||||
|
GLint interval;
|
||||||
|
CGLGetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
|
||||||
|
return interval != 0;
|
||||||
#else
|
#else
|
||||||
|
// TODO: Fill in for linux
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -647,12 +661,13 @@ void OpenGLDisplayPlugin::withMainThreadContext(std::function<void()> f) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage OpenGLDisplayPlugin::getScreenshot() const {
|
QImage OpenGLDisplayPlugin::getScreenshot() const {
|
||||||
QImage result;
|
using namespace oglplus;
|
||||||
|
QImage screenshot(_compositeFramebuffer->size.x, _compositeFramebuffer->size.y, QImage::Format_RGBA8888);
|
||||||
withMainThreadContext([&] {
|
withMainThreadContext([&] {
|
||||||
static auto widget = _container->getPrimaryWidget();
|
Framebuffer::Bind(Framebuffer::Target::Read, _compositeFramebuffer->fbo);
|
||||||
result = widget->grabFrameBuffer();
|
Context::ReadPixels(0, 0, _compositeFramebuffer->size.x, _compositeFramebuffer->size.y, enums::PixelDataFormat::RGBA, enums::PixelDataType::UnsignedByte, screenshot.bits());
|
||||||
});
|
});
|
||||||
return result;
|
return screenshot.mirrored(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t OpenGLDisplayPlugin::getSceneTextureId() const {
|
uint32_t OpenGLDisplayPlugin::getSceneTextureId() const {
|
||||||
|
|
|
@ -21,6 +21,11 @@
|
||||||
#include <gl/GLWidget.h>
|
#include <gl/GLWidget.h>
|
||||||
#include <shared/NsightHelpers.h>
|
#include <shared/NsightHelpers.h>
|
||||||
|
|
||||||
|
#include <gpu/DrawUnitQuadTexcoord_vert.h>
|
||||||
|
#include <gpu/DrawTexture_frag.h>
|
||||||
|
|
||||||
|
#include <PathUtils.h>
|
||||||
|
|
||||||
#include "../Logging.h"
|
#include "../Logging.h"
|
||||||
#include "../CompositorHelper.h"
|
#include "../CompositorHelper.h"
|
||||||
|
|
||||||
|
@ -58,9 +63,33 @@ bool HmdDisplayPlugin::internalActivate() {
|
||||||
_eyeInverseProjections[eye] = glm::inverse(_eyeProjections[eye]);
|
_eyeInverseProjections[eye] = glm::inverse(_eyeProjections[eye]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (_previewTextureID == 0) {
|
||||||
|
QImage previewTexture(PathUtils::resourcesPath() + "images/preview.png");
|
||||||
|
if (!previewTexture.isNull()) {
|
||||||
|
glGenTextures(1, &_previewTextureID);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _previewTextureID);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, previewTexture.width(), previewTexture.height(), 0,
|
||||||
|
GL_BGRA, GL_UNSIGNED_BYTE, previewTexture.mirrored(false, true).bits());
|
||||||
|
using namespace oglplus;
|
||||||
|
Texture::MinFilter(TextureTarget::_2D, TextureMinFilter::Linear);
|
||||||
|
Texture::MagFilter(TextureTarget::_2D, TextureMagFilter::Linear);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
_previewAspect = ((float)previewTexture.width())/((float)previewTexture.height());
|
||||||
|
_firstPreview = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Parent::internalActivate();
|
return Parent::internalActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HmdDisplayPlugin::internalDeactivate() {
|
||||||
|
if (_previewTextureID != 0) {
|
||||||
|
glDeleteTextures(1, &_previewTextureID);
|
||||||
|
_previewTextureID = 0;
|
||||||
|
}
|
||||||
|
Parent::internalDeactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char * REPROJECTION_VS = R"VS(#version 410 core
|
static const char * REPROJECTION_VS = R"VS(#version 410 core
|
||||||
in vec3 Position;
|
in vec3 Position;
|
||||||
|
@ -196,6 +225,7 @@ static ProgramPtr getReprojectionProgram() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static GLint PREVIEW_TEXTURE_LOCATION = -1;
|
||||||
|
|
||||||
static const char * LASER_VS = R"VS(#version 410 core
|
static const char * LASER_VS = R"VS(#version 410 core
|
||||||
uniform mat4 mvp = mat4(1);
|
uniform mat4 mvp = mat4(1);
|
||||||
|
@ -227,14 +257,24 @@ void main() {
|
||||||
void HmdDisplayPlugin::customizeContext() {
|
void HmdDisplayPlugin::customizeContext() {
|
||||||
Parent::customizeContext();
|
Parent::customizeContext();
|
||||||
// Only enable mirroring if we know vsync is disabled
|
// Only enable mirroring if we know vsync is disabled
|
||||||
|
// On Mac, this won't work due to how the contexts are handled, so don't try
|
||||||
|
#if !defined(Q_OS_MAC)
|
||||||
enableVsync(false);
|
enableVsync(false);
|
||||||
|
#endif
|
||||||
_enablePreview = !isVsyncEnabled();
|
_enablePreview = !isVsyncEnabled();
|
||||||
_sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO);
|
_sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO);
|
||||||
compileProgram(_laserProgram, LASER_VS, LASER_FS);
|
|
||||||
_laserGeometry = loadLaser(_laserProgram);
|
|
||||||
compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS);
|
|
||||||
|
|
||||||
using namespace oglplus;
|
using namespace oglplus;
|
||||||
|
if (!_enablePreview) {
|
||||||
|
const std::string version("#version 410 core\n");
|
||||||
|
compileProgram(_previewProgram, version + DrawUnitQuadTexcoord_vert, version + DrawTexture_frag);
|
||||||
|
PREVIEW_TEXTURE_LOCATION = Uniform<int>(*_previewProgram, "colorMap").Location();
|
||||||
|
}
|
||||||
|
|
||||||
|
compileProgram(_laserProgram, LASER_VS, LASER_FS);
|
||||||
|
_laserGeometry = loadLaser(_laserProgram);
|
||||||
|
|
||||||
|
compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS);
|
||||||
REPROJECTION_MATRIX_LOCATION = Uniform<glm::mat3>(*_reprojectionProgram, "reprojection").Location();
|
REPROJECTION_MATRIX_LOCATION = Uniform<glm::mat3>(*_reprojectionProgram, "reprojection").Location();
|
||||||
INVERSE_PROJECTION_MATRIX_LOCATION = Uniform<glm::mat4>(*_reprojectionProgram, "inverseProjections").Location();
|
INVERSE_PROJECTION_MATRIX_LOCATION = Uniform<glm::mat4>(*_reprojectionProgram, "inverseProjections").Location();
|
||||||
PROJECTION_MATRIX_LOCATION = Uniform<glm::mat4>(*_reprojectionProgram, "projections").Location();
|
PROJECTION_MATRIX_LOCATION = Uniform<glm::mat4>(*_reprojectionProgram, "projections").Location();
|
||||||
|
@ -243,6 +283,7 @@ void HmdDisplayPlugin::customizeContext() {
|
||||||
void HmdDisplayPlugin::uncustomizeContext() {
|
void HmdDisplayPlugin::uncustomizeContext() {
|
||||||
_sphereSection.reset();
|
_sphereSection.reset();
|
||||||
_compositeFramebuffer.reset();
|
_compositeFramebuffer.reset();
|
||||||
|
_previewProgram.reset();
|
||||||
_reprojectionProgram.reset();
|
_reprojectionProgram.reset();
|
||||||
_laserProgram.reset();
|
_laserProgram.reset();
|
||||||
_laserGeometry.reset();
|
_laserGeometry.reset();
|
||||||
|
@ -335,30 +376,32 @@ void HmdDisplayPlugin::internalPresent() {
|
||||||
hmdPresent();
|
hmdPresent();
|
||||||
|
|
||||||
// screen preview mirroring
|
// screen preview mirroring
|
||||||
|
auto window = _container->getPrimaryWidget();
|
||||||
|
auto devicePixelRatio = window->devicePixelRatio();
|
||||||
|
auto windowSize = toGlm(window->size());
|
||||||
|
windowSize *= devicePixelRatio;
|
||||||
|
float windowAspect = aspect(windowSize);
|
||||||
|
float sceneAspect = _enablePreview ? aspect(_renderTargetSize) : _previewAspect;
|
||||||
|
if (_enablePreview && _monoPreview) {
|
||||||
|
sceneAspect /= 2.0f;
|
||||||
|
}
|
||||||
|
float aspectRatio = sceneAspect / windowAspect;
|
||||||
|
|
||||||
|
uvec2 targetViewportSize = windowSize;
|
||||||
|
if (aspectRatio < 1.0f) {
|
||||||
|
targetViewportSize.x *= aspectRatio;
|
||||||
|
} else {
|
||||||
|
targetViewportSize.y /= aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
uvec2 targetViewportPosition;
|
||||||
|
if (targetViewportSize.x < windowSize.x) {
|
||||||
|
targetViewportPosition.x = (windowSize.x - targetViewportSize.x) / 2;
|
||||||
|
} else if (targetViewportSize.y < windowSize.y) {
|
||||||
|
targetViewportPosition.y = (windowSize.y - targetViewportSize.y) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
if (_enablePreview) {
|
if (_enablePreview) {
|
||||||
auto window = _container->getPrimaryWidget();
|
|
||||||
auto windowSize = toGlm(window->size());
|
|
||||||
float windowAspect = aspect(windowSize);
|
|
||||||
float sceneAspect = aspect(_renderTargetSize);
|
|
||||||
if (_monoPreview) {
|
|
||||||
sceneAspect /= 2.0f;
|
|
||||||
}
|
|
||||||
float aspectRatio = sceneAspect / windowAspect;
|
|
||||||
|
|
||||||
uvec2 targetViewportSize = windowSize;
|
|
||||||
if (aspectRatio < 1.0f) {
|
|
||||||
targetViewportSize.x *= aspectRatio;
|
|
||||||
} else {
|
|
||||||
targetViewportSize.y /= aspectRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
uvec2 targetViewportPosition;
|
|
||||||
if (targetViewportSize.x < windowSize.x) {
|
|
||||||
targetViewportPosition.x = (windowSize.x - targetViewportSize.x) / 2;
|
|
||||||
} else if (targetViewportSize.y < windowSize.y) {
|
|
||||||
targetViewportPosition.y = (windowSize.y - targetViewportSize.y) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
using namespace oglplus;
|
using namespace oglplus;
|
||||||
Context::Clear().ColorBuffer();
|
Context::Clear().ColorBuffer();
|
||||||
auto sourceSize = _compositeFramebuffer->size;
|
auto sourceSize = _compositeFramebuffer->size;
|
||||||
|
@ -373,6 +416,21 @@ void HmdDisplayPlugin::internalPresent() {
|
||||||
BufferSelectBit::ColorBuffer, BlitFilter::Nearest);
|
BufferSelectBit::ColorBuffer, BlitFilter::Nearest);
|
||||||
});
|
});
|
||||||
swapBuffers();
|
swapBuffers();
|
||||||
|
} else if (_firstPreview || windowSize != _prevWindowSize || devicePixelRatio != _prevDevicePixelRatio) {
|
||||||
|
useProgram(_previewProgram);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glClearColor(0, 0, 0, 1);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glViewport(targetViewportPosition.x, targetViewportPosition.y, targetViewportSize.x, targetViewportSize.y);
|
||||||
|
glUniform1i(PREVIEW_TEXTURE_LOCATION, 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _previewTextureID);
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
swapBuffers();
|
||||||
|
_firstPreview = false;
|
||||||
|
_prevWindowSize = windowSize;
|
||||||
|
_prevDevicePixelRatio = devicePixelRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
postPreview();
|
postPreview();
|
||||||
|
|
|
@ -40,6 +40,7 @@ protected:
|
||||||
virtual void updatePresentPose();
|
virtual void updatePresentPose();
|
||||||
|
|
||||||
bool internalActivate() override;
|
bool internalActivate() override;
|
||||||
|
void internalDeactivate() override;
|
||||||
void compositeScene() override;
|
void compositeScene() override;
|
||||||
void compositeOverlay() override;
|
void compositeOverlay() override;
|
||||||
void compositePointer() override;
|
void compositePointer() override;
|
||||||
|
@ -89,8 +90,17 @@ private:
|
||||||
bool _enablePreview { false };
|
bool _enablePreview { false };
|
||||||
bool _monoPreview { true };
|
bool _monoPreview { true };
|
||||||
bool _enableReprojection { true };
|
bool _enableReprojection { true };
|
||||||
ShapeWrapperPtr _sphereSection;
|
bool _firstPreview { true };
|
||||||
|
|
||||||
|
ProgramPtr _previewProgram;
|
||||||
|
float _previewAspect { 0 };
|
||||||
|
GLuint _previewTextureID { 0 };
|
||||||
|
glm::uvec2 _prevWindowSize { 0, 0 };
|
||||||
|
qreal _prevDevicePixelRatio { 0 };
|
||||||
|
|
||||||
ProgramPtr _reprojectionProgram;
|
ProgramPtr _reprojectionProgram;
|
||||||
|
ShapeWrapperPtr _sphereSection;
|
||||||
|
|
||||||
ProgramPtr _laserProgram;
|
ProgramPtr _laserProgram;
|
||||||
ShapeWrapperPtr _laserGeometry;
|
ShapeWrapperPtr _laserGeometry;
|
||||||
};
|
};
|
||||||
|
|
|
@ -291,7 +291,9 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
||||||
foreach(const EntityItemID& entityID, _currentEntitiesInside) {
|
foreach(const EntityItemID& entityID, _currentEntitiesInside) {
|
||||||
if (!entitiesContainingAvatar.contains(entityID)) {
|
if (!entitiesContainingAvatar.contains(entityID)) {
|
||||||
emit leaveEntity(entityID);
|
emit leaveEntity(entityID);
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +301,9 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
||||||
foreach(const EntityItemID& entityID, entitiesContainingAvatar) {
|
foreach(const EntityItemID& entityID, entitiesContainingAvatar) {
|
||||||
if (!_currentEntitiesInside.contains(entityID)) {
|
if (!_currentEntitiesInside.contains(entityID)) {
|
||||||
emit enterEntity(entityID);
|
emit enterEntity(entityID);
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "enterEntity");
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(entityID, "enterEntity");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_currentEntitiesInside = entitiesContainingAvatar;
|
_currentEntitiesInside = entitiesContainingAvatar;
|
||||||
|
@ -315,7 +319,9 @@ void EntityTreeRenderer::leaveAllEntities() {
|
||||||
// for all of our previous containing entities, if they are no longer containing then send them a leave event
|
// for all of our previous containing entities, if they are no longer containing then send them a leave event
|
||||||
foreach(const EntityItemID& entityID, _currentEntitiesInside) {
|
foreach(const EntityItemID& entityID, _currentEntitiesInside) {
|
||||||
emit leaveEntity(entityID);
|
emit leaveEntity(entityID);
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_currentEntitiesInside.clear();
|
_currentEntitiesInside.clear();
|
||||||
forceRecheckEntities();
|
forceRecheckEntities();
|
||||||
|
@ -652,11 +658,15 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
emit mousePressOnEntity(rayPickResult, event);
|
emit mousePressOnEntity(rayPickResult, event);
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", MouseEvent(*event));
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", MouseEvent(*event));
|
||||||
|
}
|
||||||
|
|
||||||
_currentClickingOnEntityID = rayPickResult.entityID;
|
_currentClickingOnEntityID = rayPickResult.entityID;
|
||||||
emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
|
emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", MouseEvent(*event));
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", MouseEvent(*event));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
emit mousePressOffEntity(rayPickResult, event);
|
emit mousePressOffEntity(rayPickResult, event);
|
||||||
}
|
}
|
||||||
|
@ -677,14 +687,18 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
|
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
|
||||||
emit mouseReleaseOnEntity(rayPickResult, event);
|
emit mouseReleaseOnEntity(rayPickResult, event);
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", MouseEvent(*event));
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", MouseEvent(*event));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even if we're no longer intersecting with an entity, if we started clicking on it, and now
|
// Even if we're no longer intersecting with an entity, if we started clicking on it, and now
|
||||||
// we're releasing the button, then this is considered a clickOn event
|
// we're releasing the button, then this is considered a clickOn event
|
||||||
if (!_currentClickingOnEntityID.isInvalidID()) {
|
if (!_currentClickingOnEntityID.isInvalidID()) {
|
||||||
emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
|
emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", MouseEvent(*event));
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", MouseEvent(*event));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// makes it the unknown ID, we just released so we can't be clicking on anything
|
// makes it the unknown ID, we just released so we can't be clicking on anything
|
||||||
|
@ -707,8 +721,10 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
||||||
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking);
|
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking);
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
|
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", MouseEvent(*event));
|
if (_entitiesScriptEngine) {
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", MouseEvent(*event));
|
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", MouseEvent(*event));
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", MouseEvent(*event));
|
||||||
|
}
|
||||||
|
|
||||||
// handle the hover logic...
|
// handle the hover logic...
|
||||||
|
|
||||||
|
@ -716,19 +732,25 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
||||||
// then we need to send the hover leave.
|
// then we need to send the hover leave.
|
||||||
if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) {
|
if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) {
|
||||||
emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event));
|
emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event));
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event));
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the new hover entity does not match the previous hover entity then we are entering the new one
|
// If the new hover entity does not match the previous hover entity then we are entering the new one
|
||||||
// this is true if the _currentHoverOverEntityID is known or unknown
|
// this is true if the _currentHoverOverEntityID is known or unknown
|
||||||
if (rayPickResult.entityID != _currentHoverOverEntityID) {
|
if (rayPickResult.entityID != _currentHoverOverEntityID) {
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", MouseEvent(*event));
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", MouseEvent(*event));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and
|
// and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and
|
||||||
// we should send our hover over event
|
// we should send our hover over event
|
||||||
emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event));
|
emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event));
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", MouseEvent(*event));
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", MouseEvent(*event));
|
||||||
|
}
|
||||||
|
|
||||||
// remember what we're hovering over
|
// remember what we're hovering over
|
||||||
_currentHoverOverEntityID = rayPickResult.entityID;
|
_currentHoverOverEntityID = rayPickResult.entityID;
|
||||||
|
@ -739,7 +761,9 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
||||||
// send the hover leave for our previous entity
|
// send the hover leave for our previous entity
|
||||||
if (!_currentHoverOverEntityID.isInvalidID()) {
|
if (!_currentHoverOverEntityID.isInvalidID()) {
|
||||||
emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event));
|
emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event));
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event));
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event));
|
||||||
|
}
|
||||||
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID
|
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -748,14 +772,16 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
||||||
// not yet released the hold then this is still considered a holdingClickOnEntity event
|
// not yet released the hold then this is still considered a holdingClickOnEntity event
|
||||||
if (!_currentClickingOnEntityID.isInvalidID()) {
|
if (!_currentClickingOnEntityID.isInvalidID()) {
|
||||||
emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
|
emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", MouseEvent(*event));
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", MouseEvent(*event));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_lastMouseEvent = MouseEvent(*event);
|
_lastMouseEvent = MouseEvent(*event);
|
||||||
_lastMouseEventValid = true;
|
_lastMouseEventValid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
||||||
if (_tree && !_shuttingDown) {
|
if (_tree && !_shuttingDown && _entitiesScriptEngine) {
|
||||||
_entitiesScriptEngine->unloadEntityScript(entityID);
|
_entitiesScriptEngine->unloadEntityScript(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,7 +827,7 @@ void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID, const
|
||||||
void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, const bool reload) {
|
void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, const bool reload) {
|
||||||
if (_tree && !_shuttingDown) {
|
if (_tree && !_shuttingDown) {
|
||||||
EntityItemPointer entity = getTree()->findEntityByEntityItemID(entityID);
|
EntityItemPointer entity = getTree()->findEntityByEntityItemID(entityID);
|
||||||
if (entity && entity->shouldPreloadScript()) {
|
if (entity && entity->shouldPreloadScript() && _entitiesScriptEngine) {
|
||||||
QString scriptUrl = entity->getScript();
|
QString scriptUrl = entity->getScript();
|
||||||
scriptUrl = ResourceManager::normalizeURL(scriptUrl);
|
scriptUrl = ResourceManager::normalizeURL(scriptUrl);
|
||||||
ScriptEngine::loadEntityScript(_entitiesScriptEngine, entityID, scriptUrl, reload);
|
ScriptEngine::loadEntityScript(_entitiesScriptEngine, entityID, scriptUrl, reload);
|
||||||
|
@ -910,12 +936,16 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
|
||||||
// And now the entity scripts
|
// And now the entity scripts
|
||||||
if (isCollisionOwner(myNodeID, entityTree, idA, collision)) {
|
if (isCollisionOwner(myNodeID, entityTree, idA, collision)) {
|
||||||
emit collisionWithEntity(idA, idB, collision);
|
emit collisionWithEntity(idA, idB, collision);
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(idA, "collisionWithEntity", idB, collision);
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(idA, "collisionWithEntity", idB, collision);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCollisionOwner(myNodeID, entityTree, idA, collision)) {
|
if (isCollisionOwner(myNodeID, entityTree, idA, collision)) {
|
||||||
emit collisionWithEntity(idB, idA, collision);
|
emit collisionWithEntity(idB, idA, collision);
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(idB, "collisionWithEntity", idA, collision);
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(idB, "collisionWithEntity", idA, collision);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,7 +971,9 @@ void EntityTreeRenderer::updateZone(const EntityItemID& id) {
|
||||||
if (zone && zone->contains(_lastAvatarPosition)) {
|
if (zone && zone->contains(_lastAvatarPosition)) {
|
||||||
_currentEntitiesInside << id;
|
_currentEntitiesInside << id;
|
||||||
emit enterEntity(id);
|
emit enterEntity(id);
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(id, "enterEntity");
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(id, "enterEntity");
|
||||||
|
}
|
||||||
if (zone->getVisible()) {
|
if (zone->getVisible()) {
|
||||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(zone);
|
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(zone);
|
||||||
}
|
}
|
||||||
|
|
|
@ -904,7 +904,9 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c
|
||||||
endDecode = usecTimestampNow();
|
endDecode = usecTimestampNow();
|
||||||
|
|
||||||
const quint64 LAST_EDITED_SERVERSIDE_BUMP = 1; // usec
|
const quint64 LAST_EDITED_SERVERSIDE_BUMP = 1; // usec
|
||||||
if (!senderNode->getCanRez() && senderNode->getCanRezTmp()) {
|
if ((message.getType() == PacketType::EntityAdd ||
|
||||||
|
(message.getType() == PacketType::EntityEdit && properties.lifetimeChanged())) &&
|
||||||
|
!senderNode->getCanRez() && senderNode->getCanRezTmp()) {
|
||||||
// this node is only allowed to rez temporary entities. if need be, cap the lifetime.
|
// this node is only allowed to rez temporary entities. if need be, cap the lifetime.
|
||||||
if (properties.getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME ||
|
if (properties.getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME ||
|
||||||
properties.getLifetime() > _maxTmpEntityLifetime) {
|
properties.getLifetime() > _maxTmpEntityLifetime) {
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include <OpenGL/gl.h>
|
#include <OpenGL/gl.h>
|
||||||
#include <OpenGL/glext.h>
|
#include <OpenGL/glext.h>
|
||||||
|
#include <OpenGL/OpenGL.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -47,13 +47,16 @@ void GLWidget::initializeGL() {
|
||||||
// Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate.
|
// Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate.
|
||||||
setAutoBufferSwap(false);
|
setAutoBufferSwap(false);
|
||||||
|
|
||||||
// TODO: write the proper code for linux
|
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
if (isValid() && context() && context()->contextHandle()) {
|
if (isValid() && context() && context()->contextHandle()) {
|
||||||
_vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");;
|
#if defined(Q_OS_WIN)
|
||||||
}
|
_vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");
|
||||||
|
#elif defined(Q_OS_MAC)
|
||||||
|
_vsyncSupported = true;
|
||||||
|
#else
|
||||||
|
// TODO: write the proper code for linux
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLWidget::paintEvent(QPaintEvent* event) {
|
void GLWidget::paintEvent(QPaintEvent* event) {
|
||||||
|
|
|
@ -71,8 +71,10 @@ QScriptValue TypedArrayPrototype::subarray(qint32 begin, qint32 end) {
|
||||||
end = (end < 0) ? length + end : end;
|
end = (end < 0) ? length + end : end;
|
||||||
|
|
||||||
// here we clamp the indices to fit the array
|
// here we clamp the indices to fit the array
|
||||||
|
// note: begin offset is *inclusive* while end offset is *exclusive*
|
||||||
|
// (see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray#Parameters)
|
||||||
begin = glm::clamp(begin, 0, (length - 1));
|
begin = glm::clamp(begin, 0, (length - 1));
|
||||||
end = glm::clamp(end, 0, (length - 1));
|
end = glm::clamp(end, 0, length);
|
||||||
|
|
||||||
byteOffset += begin * bytesPerElement;
|
byteOffset += begin * bytesPerElement;
|
||||||
length = (end - begin > 0) ? end - begin : 0;
|
length = (end - begin > 0) ? end - begin : 0;
|
||||||
|
|
|
@ -88,7 +88,11 @@ QScriptValue TypedArray::construct(QScriptContext* context, QScriptEngine* engin
|
||||||
if (arrayBuffer) {
|
if (arrayBuffer) {
|
||||||
if (context->argumentCount() == 1) {
|
if (context->argumentCount() == 1) {
|
||||||
// Case for entire ArrayBuffer
|
// Case for entire ArrayBuffer
|
||||||
newObject = cls->newInstance(bufferArg, 0, arrayBuffer->size());
|
if (arrayBuffer->size() % cls->_bytesPerElement != 0) {
|
||||||
|
engine->evaluate("throw \"RangeError: byteLength is not a multiple of BYTES_PER_ELEMENT\"");
|
||||||
|
}
|
||||||
|
quint32 length = arrayBuffer->size() / cls->_bytesPerElement;
|
||||||
|
newObject = cls->newInstance(bufferArg, 0, length);
|
||||||
} else {
|
} else {
|
||||||
QScriptValue byteOffsetArg = context->argument(1);
|
QScriptValue byteOffsetArg = context->argument(1);
|
||||||
if (!byteOffsetArg.isNumber()) {
|
if (!byteOffsetArg.isNumber()) {
|
||||||
|
@ -206,6 +210,7 @@ QScriptValue propertyHelper(const QByteArray* arrayBuffer, const QScriptString&
|
||||||
QDataStream stream(*arrayBuffer);
|
QDataStream stream(*arrayBuffer);
|
||||||
stream.skipRawData(id);
|
stream.skipRawData(id);
|
||||||
|
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
T result;
|
T result;
|
||||||
stream >> result;
|
stream >> result;
|
||||||
return result;
|
return result;
|
||||||
|
@ -218,6 +223,7 @@ void setPropertyHelper(QByteArray* arrayBuffer, const QScriptString& name, uint
|
||||||
if (arrayBuffer && value.isNumber()) {
|
if (arrayBuffer && value.isNumber()) {
|
||||||
QDataStream stream(arrayBuffer, QIODevice::ReadWrite);
|
QDataStream stream(arrayBuffer, QIODevice::ReadWrite);
|
||||||
stream.skipRawData(id);
|
stream.skipRawData(id);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
stream << (T)value.toNumber();
|
stream << (T)value.toNumber();
|
||||||
}
|
}
|
||||||
|
@ -357,6 +363,7 @@ QScriptValue Float32ArrayClass::property(const QScriptValue& object, const QScri
|
||||||
if (ok && arrayBuffer) {
|
if (ok && arrayBuffer) {
|
||||||
QDataStream stream(*arrayBuffer);
|
QDataStream stream(*arrayBuffer);
|
||||||
stream.skipRawData(id);
|
stream.skipRawData(id);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
|
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
|
||||||
|
|
||||||
float result;
|
float result;
|
||||||
|
@ -375,6 +382,7 @@ void Float32ArrayClass::setProperty(QScriptValue& object, const QScriptString& n
|
||||||
if (ba && value.isNumber()) {
|
if (ba && value.isNumber()) {
|
||||||
QDataStream stream(ba, QIODevice::ReadWrite);
|
QDataStream stream(ba, QIODevice::ReadWrite);
|
||||||
stream.skipRawData(id);
|
stream.skipRawData(id);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
|
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
|
||||||
|
|
||||||
stream << (float)value.toNumber();
|
stream << (float)value.toNumber();
|
||||||
|
@ -392,6 +400,7 @@ QScriptValue Float64ArrayClass::property(const QScriptValue& object, const QScri
|
||||||
if (ok && arrayBuffer) {
|
if (ok && arrayBuffer) {
|
||||||
QDataStream stream(*arrayBuffer);
|
QDataStream stream(*arrayBuffer);
|
||||||
stream.skipRawData(id);
|
stream.skipRawData(id);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
stream.setFloatingPointPrecision(QDataStream::DoublePrecision);
|
stream.setFloatingPointPrecision(QDataStream::DoublePrecision);
|
||||||
|
|
||||||
double result;
|
double result;
|
||||||
|
@ -410,6 +419,7 @@ void Float64ArrayClass::setProperty(QScriptValue& object, const QScriptString& n
|
||||||
if (ba && value.isNumber()) {
|
if (ba && value.isNumber()) {
|
||||||
QDataStream stream(ba, QIODevice::ReadWrite);
|
QDataStream stream(ba, QIODevice::ReadWrite);
|
||||||
stream.skipRawData(id);
|
stream.skipRawData(id);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
stream.setFloatingPointPrecision(QDataStream::DoublePrecision);
|
stream.setFloatingPointPrecision(QDataStream::DoublePrecision);
|
||||||
|
|
||||||
stream << (double)value.toNumber();
|
stream << (double)value.toNumber();
|
||||||
|
|
|
@ -68,18 +68,48 @@ bool OculusLegacyDisplayPlugin::isSupported() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto hmd = ovrHmd_Create(0);
|
auto hmd = ovrHmd_Create(0);
|
||||||
|
|
||||||
|
// The Oculus SDK seems to have trouble finding the right screen sometimes, so we have to guess
|
||||||
|
// Guesses, in order of best match:
|
||||||
|
// - resolution and position match
|
||||||
|
// - resolution and one component of position match
|
||||||
|
// - resolution matches
|
||||||
|
// - position matches
|
||||||
|
// If it still picks the wrong screen, you'll have to mess with your monitor configuration
|
||||||
|
QList<int> matches({ -1, -1, -1, -1 });
|
||||||
if (hmd) {
|
if (hmd) {
|
||||||
QPoint targetPosition{ hmd->WindowsPos.x, hmd->WindowsPos.y };
|
QPoint targetPosition{ hmd->WindowsPos.x, hmd->WindowsPos.y };
|
||||||
|
QSize targetResolution{ hmd->Resolution.w, hmd->Resolution.h };
|
||||||
auto screens = qApp->screens();
|
auto screens = qApp->screens();
|
||||||
for(int i = 0; i < screens.size(); ++i) {
|
for(int i = 0; i < screens.size(); ++i) {
|
||||||
auto screen = screens[i];
|
auto screen = screens[i];
|
||||||
QPoint position = screen->geometry().topLeft();
|
QPoint position = screen->geometry().topLeft();
|
||||||
if (position == targetPosition) {
|
QSize resolution = screen->geometry().size();
|
||||||
_hmdScreen = i;
|
|
||||||
break;
|
if (position == targetPosition && resolution == targetResolution) {
|
||||||
|
matches[0] = i;
|
||||||
|
} else if ((position.x() == targetPosition.x() || position.y() == targetPosition.y()) &&
|
||||||
|
resolution == targetResolution) {
|
||||||
|
matches[1] = i;
|
||||||
|
} else if (resolution == targetResolution) {
|
||||||
|
matches[2] = i;
|
||||||
|
} else if (position == targetPosition) {
|
||||||
|
matches[3] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int screen : matches) {
|
||||||
|
if (screen != -1) {
|
||||||
|
_hmdScreen = screen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_hmdScreen == -1) {
|
||||||
|
qDebug() << "Could not find Rift screen";
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
ovr_Shutdown();
|
ovr_Shutdown();
|
||||||
return result;
|
return result;
|
||||||
|
|
192
scripts/developer/tests/loadedMachine.js
Normal file
192
scripts/developer/tests/loadedMachine.js
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
"use strict";
|
||||||
|
/*jslint vars: true, plusplus: true*/
|
||||||
|
/*globals Script, MyAvatar, Quat, Render, ScriptDiscoveryService, Window, LODManager, Entities, print*/
|
||||||
|
//
|
||||||
|
// loadedMachine.js
|
||||||
|
// scripts/developer/tests/
|
||||||
|
//
|
||||||
|
// Created by Howard Stearns on 6/6/16.
|
||||||
|
// Copyright 2016 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
|
||||||
|
//
|
||||||
|
// Characterises the performance of heavily loaded or struggling machines.
|
||||||
|
// There is no point in running this on a machine that producing the target 60 or 90 hz rendering rate.
|
||||||
|
//
|
||||||
|
// The script examines several source of load, including each running script and a couple of Entity types.
|
||||||
|
// It turns all of these off, as well as LOD management, and twirls in place to get a baseline render rate.
|
||||||
|
// Then it turns each load on, one at a time, and records a new render rate.
|
||||||
|
// At the end, it reports the ordered results (in a popup), restores the original loads and LOD management, and quits.
|
||||||
|
//
|
||||||
|
// Small performance changes are not meaningful.
|
||||||
|
// If you think you find something that is significant, you should probably run again to make sure that it isn't random variation.
|
||||||
|
// You can also compare (e.g., the baseline) for different conditions such as domain, version, server settings, etc.
|
||||||
|
// This does not profile scripts as they are used -- it merely measures the effect of having the script loaded and running quietly.
|
||||||
|
|
||||||
|
var NUMBER_OF_TWIRLS_PER_LOAD = 10;
|
||||||
|
var MILLISECONDS_PER_SECOND = 1000;
|
||||||
|
var WAIT_TIME_MILLISECONDS = MILLISECONDS_PER_SECOND;
|
||||||
|
var accumulatedRotation = 0;
|
||||||
|
var start;
|
||||||
|
var frames = 0;
|
||||||
|
var config = Render.getConfig("Stats");
|
||||||
|
var thisPath = Script.resolvePath('');
|
||||||
|
var scriptData = ScriptDiscoveryService.getRunning();
|
||||||
|
var scripts = scriptData.filter(function (datum) { return datum.name !== 'defaultScripts.js'; }).map(function (script) { return script.path; });
|
||||||
|
// If defaultScripts.js is running, we leave it running, because restarting it safely is a mess.
|
||||||
|
var otherScripts = scripts.filter(function (path) { return path !== thisPath; });
|
||||||
|
var numberLeftRunning = scriptData.length - otherScripts.length;
|
||||||
|
print('initially running', otherScripts.length, 'scripts. Leaving', numberLeftRunning, 'and stopping', otherScripts);
|
||||||
|
var typedEntities = {Light: [], ParticleEffect: []};
|
||||||
|
var interestingTypes = Object.keys(typedEntities);
|
||||||
|
var propertiedEntities = {dynamic: []};
|
||||||
|
var interestingProperties = Object.keys(propertiedEntities);
|
||||||
|
var loads = ['ignore', 'baseline'].concat(otherScripts, interestingTypes, interestingProperties);
|
||||||
|
var loadIndex = 0, nLoads = loads.length, load;
|
||||||
|
var results = [];
|
||||||
|
var initialLodIsAutomatic = LODManager.getAutomaticLODAdjust();
|
||||||
|
var SEARCH_RADIUS = 17000;
|
||||||
|
var DEFAULT_LOD = 32768 * 400;
|
||||||
|
LODManager.setAutomaticLODAdjust(false);
|
||||||
|
LODManager.setOctreeSizeScale(DEFAULT_LOD);
|
||||||
|
|
||||||
|
// Fill the typedEnties with the entityIDs that are already visible. It would be nice if this were more efficient.
|
||||||
|
var allEntities = Entities.findEntities(MyAvatar.position, SEARCH_RADIUS);
|
||||||
|
print('Searching', allEntities.length, 'entities for', interestingTypes, 'and', interestingProperties);
|
||||||
|
var propertiesToGet = ['type', 'visible'].concat(interestingProperties);
|
||||||
|
allEntities.forEach(function (entityID) {
|
||||||
|
var properties = Entities.getEntityProperties(entityID, propertiesToGet);
|
||||||
|
if (properties.visible) {
|
||||||
|
if (interestingTypes.indexOf(properties.type) >= 0) {
|
||||||
|
typedEntities[properties.type].push(entityID);
|
||||||
|
} else {
|
||||||
|
interestingProperties.forEach(function (property) {
|
||||||
|
if (entityID && properties[property]) {
|
||||||
|
propertiedEntities[property].push(entityID);
|
||||||
|
entityID = false; // Put in only one bin
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
allEntities = undefined; // free them
|
||||||
|
interestingTypes.forEach(function (type) {
|
||||||
|
print('There are', typedEntities[type].length, type, 'entities.');
|
||||||
|
});
|
||||||
|
interestingProperties.forEach(function (property) {
|
||||||
|
print('There are', propertiedEntities[property].length, property, 'entities.');
|
||||||
|
});
|
||||||
|
function toggleVisibility(type, on) {
|
||||||
|
typedEntities[type].forEach(function (entityID) {
|
||||||
|
Entities.editEntity(entityID, {visible: on});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function toggleProperty(property, on) {
|
||||||
|
propertiedEntities[property].forEach(function (entityID) {
|
||||||
|
var properties = {};
|
||||||
|
properties[property] = on;
|
||||||
|
Entities.editEntity(entityID, properties);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function restoreOneTest(load) {
|
||||||
|
print('restore', load);
|
||||||
|
switch (load) {
|
||||||
|
case 'baseline':
|
||||||
|
case 'ignore': // ignore is used to do a twirl to make sure everything is loaded.
|
||||||
|
break;
|
||||||
|
case 'Light':
|
||||||
|
case 'ParticleEffect':
|
||||||
|
toggleVisibility(load, true);
|
||||||
|
break;
|
||||||
|
case 'dynamic':
|
||||||
|
toggleProperty(load, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Script.load(load);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function undoOneTest(load) {
|
||||||
|
print('stop', load);
|
||||||
|
switch (load) {
|
||||||
|
case 'baseline':
|
||||||
|
case 'ignore':
|
||||||
|
break;
|
||||||
|
case 'Light':
|
||||||
|
case 'ParticleEffect':
|
||||||
|
toggleVisibility(load, false);
|
||||||
|
break;
|
||||||
|
case 'dynamic':
|
||||||
|
toggleProperty(load, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ScriptDiscoveryService.stopScript(load);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loads.forEach(undoOneTest);
|
||||||
|
|
||||||
|
function finalReport() {
|
||||||
|
var baseline = results[0];
|
||||||
|
results.forEach(function (result) {
|
||||||
|
result.ratio = (baseline.fps / result.fps);
|
||||||
|
});
|
||||||
|
results.sort(function (a, b) { return b.ratio - a.ratio; });
|
||||||
|
var report = 'Performance Report:\nBaseline: ' + baseline.fps.toFixed(1) + ' fps.';
|
||||||
|
results.forEach(function (result) {
|
||||||
|
report += '\n' + result.ratio.toFixed(2) + ' (' + result.fps.toFixed(1) + ' fps over ' + result.elapsed + ' seconds) for ' + result.name;
|
||||||
|
});
|
||||||
|
Window.alert(report);
|
||||||
|
LODManager.setAutomaticLODAdjust(initialLodIsAutomatic);
|
||||||
|
loads.forEach(restoreOneTest);
|
||||||
|
Script.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onNewStats() { // Accumulates frames on signal during load test
|
||||||
|
frames++;
|
||||||
|
}
|
||||||
|
var DEGREES_PER_FULL_TWIRL = 360;
|
||||||
|
var DEGREES_PER_UPDATE = 6;
|
||||||
|
function onUpdate() { // Spins on update signal during load test
|
||||||
|
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, accumulatedRotation, 0);
|
||||||
|
accumulatedRotation += DEGREES_PER_UPDATE;
|
||||||
|
if (accumulatedRotation >= (DEGREES_PER_FULL_TWIRL * NUMBER_OF_TWIRLS_PER_LOAD)) {
|
||||||
|
tearDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function startTest() {
|
||||||
|
print('start', load);
|
||||||
|
accumulatedRotation = frames = 0;
|
||||||
|
start = Date.now();
|
||||||
|
Script.update.connect(onUpdate);
|
||||||
|
config.newStats.connect(onNewStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
if (loadIndex >= nLoads) {
|
||||||
|
return finalReport();
|
||||||
|
}
|
||||||
|
load = loads[loadIndex];
|
||||||
|
restoreOneTest(load);
|
||||||
|
Script.setTimeout(startTest, WAIT_TIME_MILLISECONDS);
|
||||||
|
}
|
||||||
|
function tearDown() {
|
||||||
|
var now = Date.now();
|
||||||
|
var elapsed = (now - start) / MILLISECONDS_PER_SECOND;
|
||||||
|
Script.update.disconnect(onUpdate);
|
||||||
|
config.newStats.disconnect(onNewStats);
|
||||||
|
if (load !== 'ignore') {
|
||||||
|
results.push({name: load, fps: frames / elapsed, elapsed: elapsed});
|
||||||
|
}
|
||||||
|
undoOneTest(load);
|
||||||
|
loadIndex++;
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
function waitUntilStopped() { // Wait until all the scripts have stopped
|
||||||
|
var count = ScriptDiscoveryService.getRunning().length;
|
||||||
|
if (count === numberLeftRunning) {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
print('Still', count, 'scripts running');
|
||||||
|
Script.setTimeout(waitUntilStopped, WAIT_TIME_MILLISECONDS);
|
||||||
|
}
|
||||||
|
waitUntilStopped();
|
|
@ -9,7 +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
|
||||||
//
|
//
|
||||||
|
|
||||||
Script.include("../../libraries/unitTest.js");
|
Script.include("../../../../script-archive/libraries/unitTest.js");
|
||||||
|
|
||||||
// e.g. extractbits([0xff, 0x80, 0x00, 0x00], 23, 30); inclusive
|
// e.g. extractbits([0xff, 0x80, 0x00, 0x00], 23, 30); inclusive
|
||||||
function extractbits(bytes, lo, hi) {
|
function extractbits(bytes, lo, hi) {
|
||||||
|
@ -551,6 +551,20 @@ test('TypedArray.subarray', function () {
|
||||||
this.arrayEqual(a.subarray(-1, -4), []);
|
this.arrayEqual(a.subarray(-1, -4), []);
|
||||||
this.arrayEqual(a.subarray(1).subarray(1), [3, 4, 5]);
|
this.arrayEqual(a.subarray(1).subarray(1), [3, 4, 5]);
|
||||||
this.arrayEqual(a.subarray(1, 4).subarray(1, 2), [3]);
|
this.arrayEqual(a.subarray(1, 4).subarray(1, 2), [3]);
|
||||||
|
|
||||||
|
var a = new Float32Array(16);
|
||||||
|
a[0] = -1;
|
||||||
|
a[15] = 1/8;
|
||||||
|
this.assertEquals(a.length, 16);
|
||||||
|
this.assertEquals(a.byteLength, a.length * a.BYTES_PER_ELEMENT);
|
||||||
|
|
||||||
|
this.assertEquals(a.subarray(-12).length, 12, '[-12,)');
|
||||||
|
this.arrayEqual(a.subarray(-16), a, '[-16,)');
|
||||||
|
this.arrayEqual(a.subarray(12, 16), [0,0,0,1/8], '[12,16)');
|
||||||
|
this.arrayEqual(a.subarray(0, 4), [-1,0,0,0],'[0,4)');
|
||||||
|
this.arrayEqual(a.subarray(-16, -12), [-1,0,0,0],'[-16,-12)');
|
||||||
|
this.assertEquals(a.subarray(0, -12).length, 4,'[0,-12)');
|
||||||
|
this.arrayEqual(a.subarray(-10), a.subarray(6),'[-10,)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -706,3 +720,45 @@ test('Regression Tests', function() {
|
||||||
this.assertEquals(truncated, -minFloat32, 'smallest 32 bit float should not truncate to zero');
|
this.assertEquals(truncated, -minFloat32, 'smallest 32 bit float should not truncate to zero');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('new TypedArray(ArrayBuffer).length Tests', function() {
|
||||||
|
var uint8s = new Uint8Array([0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xff]),
|
||||||
|
buffer = uint8s.buffer;
|
||||||
|
|
||||||
|
this.assertEquals(buffer.byteLength, 8, 'buffer.length');
|
||||||
|
|
||||||
|
var _this = this;
|
||||||
|
[
|
||||||
|
'Uint8Array', 'Uint16Array', 'Uint32Array', 'Int8Array', 'Int16Array', 'Int32Array',
|
||||||
|
'Float32Array', 'Float64Array', 'Uint8ClampedArray'
|
||||||
|
].forEach(function(typeArrayName) {
|
||||||
|
var typeArray = eval(typeArrayName);
|
||||||
|
var a = new typeArray(buffer);
|
||||||
|
_this.assertEquals(a.BYTES_PER_ELEMENT, typeArrayName.match(/\d+/)[0]/8, typeArrayName+'.BYTES_PER_ELEMENT');
|
||||||
|
_this.assertEquals(a.byteLength, buffer.byteLength, typeArrayName+'.byteLength');
|
||||||
|
_this.assertEquals(a.length, buffer.byteLength / typeArray.BYTES_PER_ELEMENT, typeArrayName+'.length');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Native endianness check', function() {
|
||||||
|
var buffer = ArrayBuffer(4);
|
||||||
|
new Uint8Array(buffer).set([0xaa, 0xbb, 0xcc, 0xdd]);
|
||||||
|
var endian = { aabbccdd: 'big', ddccbbaa: 'little' }[
|
||||||
|
new Uint32Array(buffer)[0].toString(16)
|
||||||
|
];
|
||||||
|
this.assertEquals(endian, 'little');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('TypeArray byte order tests', function() {
|
||||||
|
var uint8s = new Uint8Array([0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xff]),
|
||||||
|
buffer = uint8s.buffer;
|
||||||
|
|
||||||
|
this.arrayEqual(new Uint8Array(buffer), [0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xff], "Uint8Array");
|
||||||
|
this.arrayEqual(new Uint16Array(buffer), [0x00ff, 0x0000, 0x0000, 0xff00], "Uint16Array");
|
||||||
|
this.arrayEqual(new Uint32Array(buffer), [0x000000ff, 0xff000000], "Uint32Array");
|
||||||
|
|
||||||
|
this.arrayEqual(new Int8Array(buffer), [-1,0,0,0,0,0,0,-1], "Int8Array");
|
||||||
|
this.arrayEqual(new Int16Array(buffer), [255, 0, 0, -256], "Int16Array");
|
||||||
|
|
||||||
|
this.arrayEqual(new Float32Array(buffer), [3.5733110840282835e-43, -1.7014118346046923e+38], "Float32Array");
|
||||||
|
this.arrayEqual(new Float64Array(buffer), [-5.486124068793999e+303], "Float64Array");
|
||||||
|
});
|
||||||
|
|
|
@ -221,6 +221,14 @@ function entityHasActions(entityID) {
|
||||||
return Entities.getActionIDs(entityID).length > 0;
|
return Entities.getActionIDs(entityID).length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findRayIntersection(pickRay, precise, include, exclude) {
|
||||||
|
var entities = Entities.findRayIntersection(pickRay, precise, include, exclude);
|
||||||
|
var overlays = Overlays.findRayIntersection(pickRay);
|
||||||
|
if (!overlays.intersects || (entities.intersects && (entities.distance <= overlays.distance))) {
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
return overlays;
|
||||||
|
}
|
||||||
function entityIsGrabbedByOther(entityID) {
|
function entityIsGrabbedByOther(entityID) {
|
||||||
// by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*.
|
// by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*.
|
||||||
var actionIDs = Entities.getActionIDs(entityID);
|
var actionIDs = Entities.getActionIDs(entityID);
|
||||||
|
@ -251,6 +259,10 @@ function propsArePhysical(props) {
|
||||||
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
|
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
|
||||||
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
|
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
|
||||||
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
|
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
|
||||||
|
var EDIT_SETTING = "io.highfidelity.isEditting";
|
||||||
|
function isEditing() {
|
||||||
|
return EXTERNALLY_MANAGED_2D_MINOR_MODE && Settings.getValue(EDIT_SETTING);
|
||||||
|
}
|
||||||
function isIn2DMode() {
|
function isIn2DMode() {
|
||||||
// In this version, we make our own determination of whether we're aimed a HUD element,
|
// In this version, we make our own determination of whether we're aimed a HUD element,
|
||||||
// because other scripts (such as handControllerPointer) might be using some other visualization
|
// because other scripts (such as handControllerPointer) might be using some other visualization
|
||||||
|
@ -1069,20 +1081,15 @@ function MyController(hand) {
|
||||||
|
|
||||||
var intersection;
|
var intersection;
|
||||||
if (USE_BLACKLIST === true && blacklist.length !== 0) {
|
if (USE_BLACKLIST === true && blacklist.length !== 0) {
|
||||||
intersection = Entities.findRayIntersection(pickRayBacked, true, [], blacklist);
|
intersection = findRayIntersection(pickRayBacked, true, [], blacklist);
|
||||||
} else {
|
} else {
|
||||||
intersection = Entities.findRayIntersection(pickRayBacked, true);
|
intersection = findRayIntersection(pickRayBacked, true);
|
||||||
}
|
|
||||||
|
|
||||||
var overlayIntersection = Overlays.findRayIntersection(pickRayBacked);
|
|
||||||
if (!intersection.intersects ||
|
|
||||||
(overlayIntersection.intersects && (intersection.distance > overlayIntersection.distance))) {
|
|
||||||
intersection = overlayIntersection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersection.intersects) {
|
if (intersection.intersects) {
|
||||||
return {
|
return {
|
||||||
entityID: intersection.entityID,
|
entityID: intersection.entityID,
|
||||||
|
overlayID: intersection.overlayID,
|
||||||
searchRay: pickRay,
|
searchRay: pickRay,
|
||||||
distance: Vec3.distance(pickRay.origin, intersection.intersection)
|
distance: Vec3.distance(pickRay.origin, intersection.intersection)
|
||||||
};
|
};
|
||||||
|
@ -1326,6 +1333,8 @@ function MyController(hand) {
|
||||||
if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) {
|
if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) {
|
||||||
grabbableEntities.push(rayPickInfo.entityID);
|
grabbableEntities.push(rayPickInfo.entityID);
|
||||||
}
|
}
|
||||||
|
} else if (rayPickInfo.overlayID) {
|
||||||
|
this.intersectionDistance = rayPickInfo.distance;
|
||||||
} else {
|
} else {
|
||||||
this.intersectionDistance = 0;
|
this.intersectionDistance = 0;
|
||||||
}
|
}
|
||||||
|
@ -1382,7 +1391,7 @@ function MyController(hand) {
|
||||||
// TODO: highlight the far-triggerable object?
|
// TODO: highlight the far-triggerable object?
|
||||||
}
|
}
|
||||||
} else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) {
|
} else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) {
|
||||||
if (this.triggerSmoothedGrab()) {
|
if (this.triggerSmoothedGrab() && !isEditing()) {
|
||||||
this.grabbedEntity = entity;
|
this.grabbedEntity = entity;
|
||||||
this.setState(STATE_DISTANCE_HOLDING, "distance hold '" + name + "'");
|
this.setState(STATE_DISTANCE_HOLDING, "distance hold '" + name + "'");
|
||||||
return;
|
return;
|
||||||
|
@ -1942,8 +1951,8 @@ function MyController(hand) {
|
||||||
|
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) {
|
if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) {
|
||||||
var intersection = Entities.findRayIntersection(pickRay, true);
|
var intersection = findRayIntersection(pickRay, true);
|
||||||
if (intersection.accurate) {
|
if (intersection.accurate || intersection.overlayID) {
|
||||||
this.lastPickTime = now;
|
this.lastPickTime = now;
|
||||||
if (intersection.entityID != this.grabbedEntity) {
|
if (intersection.entityID != this.grabbedEntity) {
|
||||||
this.callEntityMethodOnGrabbed("stopFarTrigger");
|
this.callEntityMethodOnGrabbed("stopFarTrigger");
|
||||||
|
|
|
@ -332,6 +332,8 @@ var toolBar = (function() {
|
||||||
entityListTool.clearEntityList();
|
entityListTool.clearEntityList();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var EDIT_SETTING = "io.highfidelity.isEditting"; // for communication with other scripts
|
||||||
|
Settings.setValue(EDIT_SETTING, false);
|
||||||
that.setActive = function(active) {
|
that.setActive = function(active) {
|
||||||
if (active != isActive) {
|
if (active != isActive) {
|
||||||
if (active && !Entities.canRez() && !Entities.canRezTmp()) {
|
if (active && !Entities.canRez() && !Entities.canRezTmp()) {
|
||||||
|
@ -341,6 +343,7 @@ var toolBar = (function() {
|
||||||
enabled: active
|
enabled: active
|
||||||
}));
|
}));
|
||||||
isActive = active;
|
isActive = active;
|
||||||
|
Settings.setValue(EDIT_SETTING, active);
|
||||||
if (!isActive) {
|
if (!isActive) {
|
||||||
entityListTool.setVisible(false);
|
entityListTool.setVisible(false);
|
||||||
gridTool.setVisible(false);
|
gridTool.setVisible(false);
|
||||||
|
@ -348,6 +351,7 @@ var toolBar = (function() {
|
||||||
propertiesTool.setVisible(false);
|
propertiesTool.setVisible(false);
|
||||||
selectionManager.clearSelections();
|
selectionManager.clearSelections();
|
||||||
cameraManager.disable();
|
cameraManager.disable();
|
||||||
|
selectionDisplay.triggerMapping.disable();
|
||||||
} else {
|
} else {
|
||||||
UserActivityLogger.enabledEdit();
|
UserActivityLogger.enabledEdit();
|
||||||
hasShownPropertiesTool = false;
|
hasShownPropertiesTool = false;
|
||||||
|
@ -356,6 +360,7 @@ var toolBar = (function() {
|
||||||
grid.setEnabled(true);
|
grid.setEnabled(true);
|
||||||
propertiesTool.setVisible(true);
|
propertiesTool.setVisible(true);
|
||||||
// Not sure what the following was meant to accomplish, but it currently causes
|
// Not sure what the following was meant to accomplish, but it currently causes
|
||||||
|
selectionDisplay.triggerMapping.enable();
|
||||||
// everybody else to think that Interface has lost focus overall. fogbugzid:558
|
// everybody else to think that Interface has lost focus overall. fogbugzid:558
|
||||||
// Window.setFocus();
|
// Window.setFocus();
|
||||||
}
|
}
|
||||||
|
@ -1438,6 +1443,9 @@ function pushCommandForSelections(createdEntityData, deletedEntityData) {
|
||||||
var entityID = SelectionManager.selections[i];
|
var entityID = SelectionManager.selections[i];
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID];
|
var initialProperties = SelectionManager.savedProperties[entityID];
|
||||||
var currentProperties = Entities.getEntityProperties(entityID);
|
var currentProperties = Entities.getEntityProperties(entityID);
|
||||||
|
if (!initialProperties) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
undoData.setProperties.push({
|
undoData.setProperties.push({
|
||||||
entityID: entityID,
|
entityID: entityID,
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
@ -1005,6 +1005,56 @@ SelectionDisplay = (function() {
|
||||||
var activeTool = null;
|
var activeTool = null;
|
||||||
var grabberTools = {};
|
var grabberTools = {};
|
||||||
|
|
||||||
|
// We get mouseMoveEvents from the handControllers, via handControllerPointer.
|
||||||
|
// But we dont' get mousePressEvents.
|
||||||
|
that.triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click');
|
||||||
|
Script.scriptEnding.connect(that.triggerMapping.disable);
|
||||||
|
that.TRIGGER_GRAB_VALUE = 0.85; // From handControllerGrab/Pointer.js. Should refactor.
|
||||||
|
that.TRIGGER_ON_VALUE = 0.4;
|
||||||
|
that.TRIGGER_OFF_VALUE = 0.15;
|
||||||
|
that.triggered = false;
|
||||||
|
var activeHand = Controller.Standard.RightHand;
|
||||||
|
function makeTriggerHandler(hand) {
|
||||||
|
return function (value) {
|
||||||
|
if (!that.triggered && (value > that.TRIGGER_GRAB_VALUE)) { // should we smooth?
|
||||||
|
that.triggered = true;
|
||||||
|
if (activeHand !== hand) {
|
||||||
|
// No switching while the other is already triggered, so no need to release.
|
||||||
|
activeHand = (activeHand === Controller.Standard.RightHand) ? Controller.Standard.LeftHand : Controller.Standard.RightHand;
|
||||||
|
}
|
||||||
|
var eventResult = that.mousePressEvent({});
|
||||||
|
if (!eventResult || (eventResult === 'selectionBox')) {
|
||||||
|
var pickRay = controllerComputePickRay();
|
||||||
|
if (pickRay) {
|
||||||
|
var entityIntersection = Entities.findRayIntersection(pickRay, true);
|
||||||
|
var overlayIntersection = Overlays.findRayIntersection(pickRay);
|
||||||
|
if (entityIntersection.intersects &&
|
||||||
|
(!overlayIntersection.intersects || (entityIntersection.distance < overlayIntersection.distance))) {
|
||||||
|
selectionManager.setSelections([entityIntersection.entityID]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (that.triggered && (value < that.TRIGGER_OFF_VALUE)) {
|
||||||
|
that.triggered = false;
|
||||||
|
that.mouseReleaseEvent({});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
that.triggerMapping.from(Controller.Standard.RT).peek().to(makeTriggerHandler(Controller.Standard.RightHand));
|
||||||
|
that.triggerMapping.from(Controller.Standard.LT).peek().to(makeTriggerHandler(Controller.Standard.LeftHand));
|
||||||
|
function controllerComputePickRay() {
|
||||||
|
var controllerPose = Controller.getPoseValue(activeHand);
|
||||||
|
if (controllerPose.valid && that.triggered) {
|
||||||
|
var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation),
|
||||||
|
MyAvatar.position);
|
||||||
|
// This gets point direction right, but if you want general quaternion it would be more complicated:
|
||||||
|
var controllerDirection = Quat.getUp(Quat.multiply(MyAvatar.orientation, controllerPose.rotation));
|
||||||
|
return {origin: controllerPosition, direction: controllerDirection};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function generalComputePickRay(x, y) {
|
||||||
|
return controllerComputePickRay() || Camera.computePickRay(x, y);
|
||||||
|
}
|
||||||
function addGrabberTool(overlay, tool) {
|
function addGrabberTool(overlay, tool) {
|
||||||
grabberTools[overlay] = {
|
grabberTools[overlay] = {
|
||||||
mode: tool.mode,
|
mode: tool.mode,
|
||||||
|
@ -1047,7 +1097,7 @@ SelectionDisplay = (function() {
|
||||||
lastCameraOrientation = Camera.getOrientation();
|
lastCameraOrientation = Camera.getOrientation();
|
||||||
|
|
||||||
if (event !== false) {
|
if (event !== false) {
|
||||||
pickRay = Camera.computePickRay(event.x, event.y);
|
pickRay = generalComputePickRay(event.x, event.y);
|
||||||
|
|
||||||
var wantDebug = false;
|
var wantDebug = false;
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
|
@ -2269,7 +2319,7 @@ SelectionDisplay = (function() {
|
||||||
startPosition = SelectionManager.worldPosition;
|
startPosition = SelectionManager.worldPosition;
|
||||||
var dimensions = SelectionManager.worldDimensions;
|
var dimensions = SelectionManager.worldDimensions;
|
||||||
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = generalComputePickRay(event.x, event.y);
|
||||||
initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, {
|
initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 1,
|
y: 1,
|
||||||
|
@ -2312,7 +2362,7 @@ SelectionDisplay = (function() {
|
||||||
},
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
var wantDebug = false;
|
var wantDebug = false;
|
||||||
pickRay = Camera.computePickRay(event.x, event.y);
|
pickRay = generalComputePickRay(event.x, event.y);
|
||||||
|
|
||||||
var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, {
|
var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, {
|
||||||
x: 0,
|
x: 0,
|
||||||
|
@ -2422,6 +2472,9 @@ SelectionDisplay = (function() {
|
||||||
|
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
||||||
var properties = SelectionManager.savedProperties[SelectionManager.selections[i]];
|
var properties = SelectionManager.savedProperties[SelectionManager.selections[i]];
|
||||||
|
if (!properties) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
var newPosition = Vec3.sum(properties.position, {
|
var newPosition = Vec3.sum(properties.position, {
|
||||||
x: vector.x,
|
x: vector.x,
|
||||||
y: 0,
|
y: 0,
|
||||||
|
@ -2448,7 +2501,7 @@ SelectionDisplay = (function() {
|
||||||
addGrabberTool(grabberMoveUp, {
|
addGrabberTool(grabberMoveUp, {
|
||||||
mode: "TRANSLATE_UP_DOWN",
|
mode: "TRANSLATE_UP_DOWN",
|
||||||
onBegin: function(event) {
|
onBegin: function(event) {
|
||||||
pickRay = Camera.computePickRay(event.x, event.y);
|
pickRay = generalComputePickRay(event.x, event.y);
|
||||||
|
|
||||||
upDownPickNormal = Quat.getFront(lastCameraOrientation);
|
upDownPickNormal = Quat.getFront(lastCameraOrientation);
|
||||||
// Remove y component so the y-axis lies along the plane we picking on - this will
|
// Remove y component so the y-axis lies along the plane we picking on - this will
|
||||||
|
@ -2481,7 +2534,7 @@ SelectionDisplay = (function() {
|
||||||
pushCommandForSelections(duplicatedEntityIDs);
|
pushCommandForSelections(duplicatedEntityIDs);
|
||||||
},
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
pickRay = Camera.computePickRay(event.x, event.y);
|
pickRay = generalComputePickRay(event.x, event.y);
|
||||||
|
|
||||||
// translate mode left/right based on view toward entity
|
// translate mode left/right based on view toward entity
|
||||||
var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal);
|
var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal);
|
||||||
|
@ -2690,7 +2743,7 @@ SelectionDisplay = (function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
planeNormal = Vec3.multiplyQbyV(rotation, planeNormal);
|
planeNormal = Vec3.multiplyQbyV(rotation, planeNormal);
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = generalComputePickRay(event.x, event.y);
|
||||||
lastPick = rayPlaneIntersection(pickRay,
|
lastPick = rayPlaneIntersection(pickRay,
|
||||||
pickRayPosition,
|
pickRayPosition,
|
||||||
planeNormal);
|
planeNormal);
|
||||||
|
@ -2726,7 +2779,7 @@ SelectionDisplay = (function() {
|
||||||
rotation = SelectionManager.worldRotation;
|
rotation = SelectionManager.worldRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = generalComputePickRay(event.x, event.y);
|
||||||
newPick = rayPlaneIntersection(pickRay,
|
newPick = rayPlaneIntersection(pickRay,
|
||||||
pickRayPosition,
|
pickRayPosition,
|
||||||
planeNormal);
|
planeNormal);
|
||||||
|
@ -2782,10 +2835,10 @@ SelectionDisplay = (function() {
|
||||||
var wantDebug = false;
|
var wantDebug = false;
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
print(stretchMode);
|
print(stretchMode);
|
||||||
Vec3.print(" newIntersection:", newIntersection);
|
//Vec3.print(" newIntersection:", newIntersection);
|
||||||
Vec3.print(" vector:", vector);
|
Vec3.print(" vector:", vector);
|
||||||
Vec3.print(" oldPOS:", oldPOS);
|
//Vec3.print(" oldPOS:", oldPOS);
|
||||||
Vec3.print(" newPOS:", newPOS);
|
//Vec3.print(" newPOS:", newPOS);
|
||||||
Vec3.print(" changeInDimensions:", changeInDimensions);
|
Vec3.print(" changeInDimensions:", changeInDimensions);
|
||||||
Vec3.print(" newDimensions:", newDimensions);
|
Vec3.print(" newDimensions:", newDimensions);
|
||||||
|
|
||||||
|
@ -3350,7 +3403,7 @@ SelectionDisplay = (function() {
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
},
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = generalComputePickRay(event.x, event.y);
|
||||||
Overlays.editOverlay(selectionBox, {
|
Overlays.editOverlay(selectionBox, {
|
||||||
ignoreRayIntersection: true,
|
ignoreRayIntersection: true,
|
||||||
visible: false
|
visible: false
|
||||||
|
@ -3520,7 +3573,7 @@ SelectionDisplay = (function() {
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
},
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = generalComputePickRay(event.x, event.y);
|
||||||
Overlays.editOverlay(selectionBox, {
|
Overlays.editOverlay(selectionBox, {
|
||||||
ignoreRayIntersection: true,
|
ignoreRayIntersection: true,
|
||||||
visible: false
|
visible: false
|
||||||
|
@ -3682,7 +3735,7 @@ SelectionDisplay = (function() {
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
},
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = generalComputePickRay(event.x, event.y);
|
||||||
Overlays.editOverlay(selectionBox, {
|
Overlays.editOverlay(selectionBox, {
|
||||||
ignoreRayIntersection: true,
|
ignoreRayIntersection: true,
|
||||||
visible: false
|
visible: false
|
||||||
|
@ -3797,13 +3850,13 @@ SelectionDisplay = (function() {
|
||||||
|
|
||||||
that.mousePressEvent = function(event) {
|
that.mousePressEvent = function(event) {
|
||||||
var wantDebug = false;
|
var wantDebug = false;
|
||||||
if (!event.isLeftButton) {
|
if (!event.isLeftButton && !that.triggered) {
|
||||||
// if another mouse button than left is pressed ignore it
|
// if another mouse button than left is pressed ignore it
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var somethingClicked = false;
|
var somethingClicked = false;
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = generalComputePickRay(event.x, event.y);
|
||||||
|
|
||||||
// before we do a ray test for grabbers, disable the ray intersection for our selection box
|
// before we do a ray test for grabbers, disable the ray intersection for our selection box
|
||||||
Overlays.editOverlay(selectionBox, {
|
Overlays.editOverlay(selectionBox, {
|
||||||
|
@ -3837,7 +3890,7 @@ SelectionDisplay = (function() {
|
||||||
if (tool) {
|
if (tool) {
|
||||||
activeTool = tool;
|
activeTool = tool;
|
||||||
mode = tool.mode;
|
mode = tool.mode;
|
||||||
somethingClicked = true;
|
somethingClicked = 'tool';
|
||||||
if (activeTool && activeTool.onBegin) {
|
if (activeTool && activeTool.onBegin) {
|
||||||
activeTool.onBegin(event);
|
activeTool.onBegin(event);
|
||||||
}
|
}
|
||||||
|
@ -3845,7 +3898,7 @@ SelectionDisplay = (function() {
|
||||||
switch (result.overlayID) {
|
switch (result.overlayID) {
|
||||||
case grabberMoveUp:
|
case grabberMoveUp:
|
||||||
mode = "TRANSLATE_UP_DOWN";
|
mode = "TRANSLATE_UP_DOWN";
|
||||||
somethingClicked = true;
|
somethingClicked = mode;
|
||||||
|
|
||||||
// in translate mode, we hide our stretch handles...
|
// in translate mode, we hide our stretch handles...
|
||||||
for (var i = 0; i < stretchHandles.length; i++) {
|
for (var i = 0; i < stretchHandles.length; i++) {
|
||||||
|
@ -3860,34 +3913,34 @@ SelectionDisplay = (function() {
|
||||||
case grabberEdgeTN: // TODO: maybe this should be TOP+NEAR stretching?
|
case grabberEdgeTN: // TODO: maybe this should be TOP+NEAR stretching?
|
||||||
case grabberEdgeBN: // TODO: maybe this should be BOTTOM+FAR stretching?
|
case grabberEdgeBN: // TODO: maybe this should be BOTTOM+FAR stretching?
|
||||||
mode = "STRETCH_NEAR";
|
mode = "STRETCH_NEAR";
|
||||||
somethingClicked = true;
|
somethingClicked = mode;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case grabberFAR:
|
case grabberFAR:
|
||||||
case grabberEdgeTF: // TODO: maybe this should be TOP+FAR stretching?
|
case grabberEdgeTF: // TODO: maybe this should be TOP+FAR stretching?
|
||||||
case grabberEdgeBF: // TODO: maybe this should be BOTTOM+FAR stretching?
|
case grabberEdgeBF: // TODO: maybe this should be BOTTOM+FAR stretching?
|
||||||
mode = "STRETCH_FAR";
|
mode = "STRETCH_FAR";
|
||||||
somethingClicked = true;
|
somethingClicked = mode;
|
||||||
break;
|
break;
|
||||||
case grabberTOP:
|
case grabberTOP:
|
||||||
mode = "STRETCH_TOP";
|
mode = "STRETCH_TOP";
|
||||||
somethingClicked = true;
|
somethingClicked = mode;
|
||||||
break;
|
break;
|
||||||
case grabberBOTTOM:
|
case grabberBOTTOM:
|
||||||
mode = "STRETCH_BOTTOM";
|
mode = "STRETCH_BOTTOM";
|
||||||
somethingClicked = true;
|
somethingClicked = mode;
|
||||||
break;
|
break;
|
||||||
case grabberRIGHT:
|
case grabberRIGHT:
|
||||||
case grabberEdgeTR: // TODO: maybe this should be TOP+RIGHT stretching?
|
case grabberEdgeTR: // TODO: maybe this should be TOP+RIGHT stretching?
|
||||||
case grabberEdgeBR: // TODO: maybe this should be BOTTOM+RIGHT stretching?
|
case grabberEdgeBR: // TODO: maybe this should be BOTTOM+RIGHT stretching?
|
||||||
mode = "STRETCH_RIGHT";
|
mode = "STRETCH_RIGHT";
|
||||||
somethingClicked = true;
|
somethingClicked = mode;
|
||||||
break;
|
break;
|
||||||
case grabberLEFT:
|
case grabberLEFT:
|
||||||
case grabberEdgeTL: // TODO: maybe this should be TOP+LEFT stretching?
|
case grabberEdgeTL: // TODO: maybe this should be TOP+LEFT stretching?
|
||||||
case grabberEdgeBL: // TODO: maybe this should be BOTTOM+LEFT stretching?
|
case grabberEdgeBL: // TODO: maybe this should be BOTTOM+LEFT stretching?
|
||||||
mode = "STRETCH_LEFT";
|
mode = "STRETCH_LEFT";
|
||||||
somethingClicked = true;
|
somethingClicked = mode;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -3955,7 +4008,7 @@ SelectionDisplay = (function() {
|
||||||
if (tool) {
|
if (tool) {
|
||||||
activeTool = tool;
|
activeTool = tool;
|
||||||
mode = tool.mode;
|
mode = tool.mode;
|
||||||
somethingClicked = true;
|
somethingClicked = 'tool';
|
||||||
if (activeTool && activeTool.onBegin) {
|
if (activeTool && activeTool.onBegin) {
|
||||||
activeTool.onBegin(event);
|
activeTool.onBegin(event);
|
||||||
}
|
}
|
||||||
|
@ -3963,7 +4016,7 @@ SelectionDisplay = (function() {
|
||||||
switch (result.overlayID) {
|
switch (result.overlayID) {
|
||||||
case yawHandle:
|
case yawHandle:
|
||||||
mode = "ROTATE_YAW";
|
mode = "ROTATE_YAW";
|
||||||
somethingClicked = true;
|
somethingClicked = mode;
|
||||||
overlayOrientation = yawHandleRotation;
|
overlayOrientation = yawHandleRotation;
|
||||||
overlayCenter = yawCenter;
|
overlayCenter = yawCenter;
|
||||||
yawZero = result.intersection;
|
yawZero = result.intersection;
|
||||||
|
@ -3973,7 +4026,7 @@ SelectionDisplay = (function() {
|
||||||
case pitchHandle:
|
case pitchHandle:
|
||||||
mode = "ROTATE_PITCH";
|
mode = "ROTATE_PITCH";
|
||||||
initialPosition = SelectionManager.worldPosition;
|
initialPosition = SelectionManager.worldPosition;
|
||||||
somethingClicked = true;
|
somethingClicked = mode;
|
||||||
overlayOrientation = pitchHandleRotation;
|
overlayOrientation = pitchHandleRotation;
|
||||||
overlayCenter = pitchCenter;
|
overlayCenter = pitchCenter;
|
||||||
pitchZero = result.intersection;
|
pitchZero = result.intersection;
|
||||||
|
@ -3982,7 +4035,7 @@ SelectionDisplay = (function() {
|
||||||
|
|
||||||
case rollHandle:
|
case rollHandle:
|
||||||
mode = "ROTATE_ROLL";
|
mode = "ROTATE_ROLL";
|
||||||
somethingClicked = true;
|
somethingClicked = mode;
|
||||||
overlayOrientation = rollHandleRotation;
|
overlayOrientation = rollHandleRotation;
|
||||||
overlayCenter = rollCenter;
|
overlayCenter = rollCenter;
|
||||||
rollZero = result.intersection;
|
rollZero = result.intersection;
|
||||||
|
@ -4156,7 +4209,7 @@ SelectionDisplay = (function() {
|
||||||
|
|
||||||
mode = translateXZTool.mode;
|
mode = translateXZTool.mode;
|
||||||
activeTool.onBegin(event);
|
activeTool.onBegin(event);
|
||||||
somethingClicked = true;
|
somethingClicked = 'selectionBox';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
|
@ -4169,7 +4222,7 @@ SelectionDisplay = (function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (somethingClicked) {
|
if (somethingClicked) {
|
||||||
pickRay = Camera.computePickRay(event.x, event.y);
|
pickRay = generalComputePickRay(event.x, event.y);
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
|
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
|
||||||
}
|
}
|
||||||
|
@ -4201,7 +4254,7 @@ SelectionDisplay = (function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no tool is active, then just look for handles to highlight...
|
// if no tool is active, then just look for handles to highlight...
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = generalComputePickRay(event.x, event.y);
|
||||||
var result = Overlays.findRayIntersection(pickRay);
|
var result = Overlays.findRayIntersection(pickRay);
|
||||||
var pickedColor;
|
var pickedColor;
|
||||||
var pickedAlpha;
|
var pickedAlpha;
|
||||||
|
@ -4320,7 +4373,7 @@ SelectionDisplay = (function() {
|
||||||
that.updateHandleSizes = function() {
|
that.updateHandleSizes = function() {
|
||||||
if (selectionManager.hasSelection()) {
|
if (selectionManager.hasSelection()) {
|
||||||
var diff = Vec3.subtract(selectionManager.worldPosition, Camera.getPosition());
|
var diff = Vec3.subtract(selectionManager.worldPosition, Camera.getPosition());
|
||||||
var grabberSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 2;
|
var grabberSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 5;
|
||||||
var dimensions = SelectionManager.worldDimensions;
|
var dimensions = SelectionManager.worldDimensions;
|
||||||
var avgDimension = (dimensions.x + dimensions.y + dimensions.z) / 3;
|
var avgDimension = (dimensions.x + dimensions.y + dimensions.z) / 3;
|
||||||
grabberSize = Math.min(grabberSize, avgDimension / 10);
|
grabberSize = Math.min(grabberSize, avgDimension / 10);
|
||||||
|
|
|
@ -344,6 +344,7 @@ var usersWindow = (function () {
|
||||||
windowTextHeight,
|
windowTextHeight,
|
||||||
windowLineSpacing,
|
windowLineSpacing,
|
||||||
windowLineHeight, // = windowTextHeight + windowLineSpacing
|
windowLineHeight, // = windowTextHeight + windowLineSpacing
|
||||||
|
windowMinimumHeight,
|
||||||
|
|
||||||
usersOnline, // Raw users data
|
usersOnline, // Raw users data
|
||||||
linesOfUsers = [], // Array of indexes pointing into usersOnline
|
linesOfUsers = [], // Array of indexes pointing into usersOnline
|
||||||
|
@ -435,6 +436,11 @@ var usersWindow = (function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saturateWindowPosition() {
|
||||||
|
windowPosition.x = Math.max(0, Math.min(viewport.x - WINDOW_WIDTH, windowPosition.x));
|
||||||
|
windowPosition.y = Math.max(windowMinimumHeight, Math.min(viewport.y, windowPosition.y));
|
||||||
|
}
|
||||||
|
|
||||||
function updateOverlayPositions() {
|
function updateOverlayPositions() {
|
||||||
// Overlay positions are all relative to windowPosition; windowPosition is the position of the windowPane overlay.
|
// Overlay positions are all relative to windowPosition; windowPosition is the position of the windowPane overlay.
|
||||||
var windowLeft = windowPosition.x,
|
var windowLeft = windowPosition.x,
|
||||||
|
@ -826,6 +832,10 @@ var usersWindow = (function () {
|
||||||
function onMouseMoveEvent(event) {
|
function onMouseMoveEvent(event) {
|
||||||
var isVisible;
|
var isVisible;
|
||||||
|
|
||||||
|
if (!isLoggedIn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isMovingScrollbar) {
|
if (isMovingScrollbar) {
|
||||||
if (scrollbarBackgroundPosition.x - WINDOW_MARGIN <= event.x
|
if (scrollbarBackgroundPosition.x - WINDOW_MARGIN <= event.x
|
||||||
&& event.x <= scrollbarBackgroundPosition.x + SCROLLBAR_BACKGROUND_WIDTH + WINDOW_MARGIN
|
&& event.x <= scrollbarBackgroundPosition.x + SCROLLBAR_BACKGROUND_WIDTH + WINDOW_MARGIN
|
||||||
|
@ -850,6 +860,8 @@ var usersWindow = (function () {
|
||||||
x: event.x - movingClickOffset.x,
|
x: event.x - movingClickOffset.x,
|
||||||
y: event.y - movingClickOffset.y
|
y: event.y - movingClickOffset.y
|
||||||
};
|
};
|
||||||
|
|
||||||
|
saturateWindowPosition();
|
||||||
calculateWindowHeight();
|
calculateWindowHeight();
|
||||||
updateOverlayPositions();
|
updateOverlayPositions();
|
||||||
updateUsersDisplay();
|
updateUsersDisplay();
|
||||||
|
@ -943,6 +955,7 @@ var usersWindow = (function () {
|
||||||
windowTextHeight = Math.floor(Overlays.textSize(textSizeOverlay, "1").height);
|
windowTextHeight = Math.floor(Overlays.textSize(textSizeOverlay, "1").height);
|
||||||
windowLineSpacing = Math.floor(Overlays.textSize(textSizeOverlay, "1\n2").height - 2 * windowTextHeight);
|
windowLineSpacing = Math.floor(Overlays.textSize(textSizeOverlay, "1\n2").height - 2 * windowTextHeight);
|
||||||
windowLineHeight = windowTextHeight + windowLineSpacing;
|
windowLineHeight = windowTextHeight + windowLineSpacing;
|
||||||
|
windowMinimumHeight = windowTextHeight + WINDOW_MARGIN + WINDOW_BASE_MARGIN;
|
||||||
Overlays.deleteOverlay(textSizeOverlay);
|
Overlays.deleteOverlay(textSizeOverlay);
|
||||||
|
|
||||||
viewport = Controller.getViewportDimensions();
|
viewport = Controller.getViewportDimensions();
|
||||||
|
@ -954,7 +967,6 @@ var usersWindow = (function () {
|
||||||
if (offset.hasOwnProperty("x") && offset.hasOwnProperty("y")) {
|
if (offset.hasOwnProperty("x") && offset.hasOwnProperty("y")) {
|
||||||
windowPosition.x = offset.x < 0 ? viewport.x + offset.x : offset.x;
|
windowPosition.x = offset.x < 0 ? viewport.x + offset.x : offset.x;
|
||||||
windowPosition.y = offset.y <= 0 ? viewport.y + offset.y : offset.y;
|
windowPosition.y = offset.y <= 0 ? viewport.y + offset.y : offset.y;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
hmdViewport = Controller.getRecommendedOverlayRect();
|
hmdViewport = Controller.getRecommendedOverlayRect();
|
||||||
windowPosition = {
|
windowPosition = {
|
||||||
|
@ -963,6 +975,7 @@ var usersWindow = (function () {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saturateWindowPosition();
|
||||||
calculateWindowHeight();
|
calculateWindowHeight();
|
||||||
|
|
||||||
windowBorder = Overlays.addOverlay("rectangle", {
|
windowBorder = Overlays.addOverlay("rectangle", {
|
||||||
|
|
Loading…
Reference in a new issue