mirror of
https://github.com/overte-org/overte.git
synced 2025-04-10 16:12:28 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into 19508
Conflicts: interface/src/Menu.h
This commit is contained in:
commit
939c17d0be
148 changed files with 7310 additions and 1484 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -39,7 +39,8 @@ interface/external/sixense/*
|
|||
# Ignore Visage
|
||||
interface/external/visage/*
|
||||
!interface/external/visage/readme.txt
|
||||
interface/resources/visage/
|
||||
interface/resources/visage/*
|
||||
!interface/resources/visage/tracker.cfg
|
||||
|
||||
# Ignore interfaceCache for Linux users
|
||||
interface/interfaceCache/
|
||||
interface/interfaceCache/
|
||||
|
|
28
BUILD.md
28
BUILD.md
|
@ -4,6 +4,7 @@ Dependencies
|
|||
* [Qt](http://qt-project.org/downloads) ~> 5.2.0
|
||||
* [zLib](http://www.zlib.net/) ~> 1.2.8
|
||||
* [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.0
|
||||
* [qxmpp](https://code.google.com/p/qxmpp/) ~> 0.7.6
|
||||
|
||||
#####Linux only
|
||||
* [freeglut](http://freeglut.sourceforge.net/) ~> 2.8.0
|
||||
|
@ -53,9 +54,16 @@ Should you choose not to install Qt5 via a package manager that handles dependen
|
|||
#####Package Managers
|
||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all hifi dependencies very simple.
|
||||
|
||||
brew install cmake qt5 glm zlib
|
||||
brew tap highfidelity/homebrew-formulas
|
||||
brew install cmake glm zlib
|
||||
brew install highfidelity/formulas/qt5
|
||||
brew link qt5 --force
|
||||
brew install highfidelity/formulas/qxmpp
|
||||
|
||||
We have a [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) that you can use/tap to install some of the dependencies. In the code block above qt5 and qxmpp are installed from formulas in this repository.
|
||||
|
||||
*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.2.0 stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.*
|
||||
|
||||
*High Fidelity has a [homebrew formula](https://raw.github.com/highfidelity/hifi/master/qt5.rb) for a patched version of Qt 5.2.0 stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.*
|
||||
#####Xcode
|
||||
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
||||
|
||||
|
@ -94,7 +102,7 @@ NOTE: zLib should configure itself correctly on install. However, sometimes zLib
|
|||
####External Libraries
|
||||
We don't currently have a Windows installer, so before running Interface, you will need to ensure that all required resources are loadable.
|
||||
|
||||
CMake will need to know where the headers and libraries for required external dependencies are. If you installed ZLIB using the installer, the FindZLIB cmake module will be able to find it. This isn't the case for glm, freeglut, and GLEW.
|
||||
CMake will need to know where the headers and libraries for required external dependencies are. If you installed ZLIB using the installer, the FindZLIB cmake module will be able to find it. This isn't the case for the others.
|
||||
|
||||
You have the choice of setting a variable specific to each library, or having a folder using a defined structure that contains all of the libs.
|
||||
|
||||
|
@ -112,11 +120,14 @@ The recommended route is to place all of the dependencies in one place and set o
|
|||
-> bin
|
||||
-> include
|
||||
-> lib
|
||||
|
||||
For all three external libraries you should be able to simply copy the extracted folder that you get from the download links provided at the top of the guide. The `root_lib_dir` in the above example can be wherever you choose on your system - as long as the environment variable HIFI_LIB_DIR is set to it.
|
||||
-> qxmpp
|
||||
-> include
|
||||
-> lib
|
||||
|
||||
*NOTE: Be careful with glm. For the folder other libraries would normally call 'include', the folder containing the headers, glm opts to use 'glm'. You will have a glm folder nested inside the top-level glm folder.*
|
||||
|
||||
For many of the external libraries where precompiled binaries are readily available you should be able to simply copy the extracted folder that you get from the download links provided at the top of the guide. Otherwise you may need to build from source and install the built product to this directory. The `root_lib_dir` in the above example can be wherever you choose on your system - as long as the environment variable HIFI_LIB_DIR is set to it.
|
||||
|
||||
Should you want to define a location for each library, these are the associated variables you will want to set:
|
||||
|
||||
`GLM_ROOT_DIR, GLUT_ROOT_DIR, GLEW_ROOT_DIR`
|
||||
|
@ -125,8 +136,10 @@ They can be set in your ENV or by passing them to the cmake command on the comma
|
|||
|
||||
Each of those designates the root directory that contains the sub-folders for each library. For example, if the GLEW_ROOT_DIR is `C:\libs\glew`, then we would expect to find an `include` folder and a `lib` folder inside `C:\libs\glew`.
|
||||
|
||||
####Freeglut DLL
|
||||
As with the Qt libraries, you will need to make sure the directory containing `freeglut.dll` is in your path. The directory to add to your path in which the DLL is found is `FREEGLUT_DIR/bin`. If you are on 64-bit windows, the directory in your path should be the x64 subdirectory in `bin`.
|
||||
*NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit version of libraries for interface.exe to run. The 32-bit version of the static library is the one linked by our CMake find modules*
|
||||
|
||||
#### DLLs
|
||||
As with the Qt libraries, you will need to make sure the directory containing dynamically-linked libraries is in your path. For example, for a dynamically linked build of freeglut, the directory to add to your path in which the DLL is found is `FREEGLUT_DIR/bin`. Where possible, you can use static builds of the external dependencies to avoid this requirement.
|
||||
|
||||
####Building in Visual Studio
|
||||
Follow the same build steps from the CMake section, but pass a different generator to CMake.
|
||||
|
@ -136,7 +149,6 @@ Follow the same build steps from the CMake section, but pass a different generat
|
|||
####Running Interface
|
||||
If you need to debug Interface, you can run interface from within Visual Studio (see the section below). You can also run Interface by launching it from command line or File Explorer from $YOUR_HIFI_PATH\build\interface\Debug\interface.exe
|
||||
|
||||
|
||||
####Debugging Interface
|
||||
* In the Solution Explorer, right click interface and click Set as StartUp Project
|
||||
* Set the "Working Directory" for the Interface debugging sessions to the Debug output directory so that your application can load resources. Do this: right click interface and click Properties, choose Debugging from Configuration Properties, set Working Directory to .\Debug
|
||||
|
|
|
@ -5,6 +5,7 @@ if (WIN32)
|
|||
endif (WIN32)
|
||||
|
||||
project(hifi)
|
||||
add_definitions(-DGLM_FORCE_RADIANS)
|
||||
|
||||
if (WIN32)
|
||||
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
|
||||
|
|
|
@ -78,9 +78,9 @@ glm::vec3 bugDirection = glm::vec3(0, 0, 1);
|
|||
const int VOXELS_PER_BUG = 18;
|
||||
glm::vec3 bugPathCenter = glm::vec3(0.25f,0.15f,0.25f); // glm::vec3(BUG_VOXEL_SIZE * 150.0, BUG_VOXEL_SIZE * 30.0, BUG_VOXEL_SIZE * 150.0);
|
||||
float bugPathRadius = 0.2f; //BUG_VOXEL_SIZE * 140.0;
|
||||
float bugPathTheta = 0.0 * PI_OVER_180;
|
||||
float bugRotation = 0.0 * PI_OVER_180;
|
||||
float bugAngleDelta = 0.2 * PI_OVER_180;
|
||||
float bugPathTheta = 0.0f * RADIANS_PER_DEGREE;
|
||||
float bugRotation = 0.0f * RADIANS_PER_DEGREE;
|
||||
float bugAngleDelta = 0.2f * RADIANS_PER_DEGREE;
|
||||
bool moveBugInLine = false;
|
||||
|
||||
class BugPart {
|
||||
|
@ -160,11 +160,11 @@ static void renderMovingBug() {
|
|||
bugPosition.z += (bugDirection.z * BUG_VOXEL_SIZE);
|
||||
|
||||
// Check boundaries
|
||||
if (bugPosition.z > 1.0) {
|
||||
bugDirection.z = -1;
|
||||
if (bugPosition.z > 1.0f) {
|
||||
bugDirection.z = -1.f;
|
||||
}
|
||||
if (bugPosition.z < BUG_VOXEL_SIZE) {
|
||||
bugDirection.z = 1;
|
||||
bugDirection.z = 1.f;
|
||||
}
|
||||
} else {
|
||||
|
||||
|
@ -174,9 +174,9 @@ static void renderMovingBug() {
|
|||
bugRotation -= bugAngleDelta; // rotate slightly
|
||||
|
||||
// If we loop past end of circle, just reset back into normal range
|
||||
if (bugPathTheta > (360.0f * PI_OVER_180)) {
|
||||
bugPathTheta = 0;
|
||||
bugRotation = 0;
|
||||
if (bugPathTheta > TWO_PI) {
|
||||
bugPathTheta = 0.f;
|
||||
bugRotation = 0.f;
|
||||
}
|
||||
|
||||
float x = bugPathCenter.x + bugPathRadius * cos(bugPathTheta);
|
||||
|
@ -225,7 +225,7 @@ static void sendVoxelBlinkMessage() {
|
|||
VoxelDetail detail;
|
||||
detail.s = BEACON_SIZE;
|
||||
|
||||
glm::vec3 position = glm::vec3(0, 0, detail.s);
|
||||
glm::vec3 position = glm::vec3(0.f, 0.f, detail.s);
|
||||
|
||||
detail.x = detail.s * floor(position.x / detail.s);
|
||||
detail.y = detail.s * floor(position.y / detail.s);
|
||||
|
@ -364,7 +364,6 @@ float danceFloorGradientIncrement = 1.0f / FRAMES_PER_BEAT;
|
|||
const float DANCE_FLOOR_MAX_GRADIENT = 1.0f;
|
||||
const float DANCE_FLOOR_MIN_GRADIENT = 0.0f;
|
||||
const int DANCE_FLOOR_VOXELS_PER_PACKET = 100;
|
||||
const int PACKETS_PER_DANCE_FLOOR = DANCE_FLOOR_VOXELS_PER_PACKET / (DANCE_FLOOR_WIDTH * DANCE_FLOOR_LENGTH);
|
||||
int danceFloorColors[DANCE_FLOOR_WIDTH][DANCE_FLOOR_LENGTH];
|
||||
|
||||
void sendDanceFloor() {
|
||||
|
@ -467,8 +466,6 @@ const float BILLBOARD_MAX_GRADIENT = 1.0f;
|
|||
const float BILLBOARD_MIN_GRADIENT = 0.0f;
|
||||
const float BILLBOARD_LIGHT_SIZE = 0.125f / TREE_SCALE; // approximately 1/8 meter per light
|
||||
const int VOXELS_PER_PACKET = 81;
|
||||
const int PACKETS_PER_BILLBOARD = VOXELS_PER_PACKET / (BILLBOARD_HEIGHT * BILLBOARD_WIDTH);
|
||||
|
||||
|
||||
// top to bottom...
|
||||
bool billboardMessage[BILLBOARD_HEIGHT][BILLBOARD_WIDTH] = {
|
||||
|
@ -541,14 +538,12 @@ static void sendBillboard() {
|
|||
}
|
||||
|
||||
bool roadInitialized = false;
|
||||
const int ROAD_WIDTH_METERS = 3.0f;
|
||||
const int BRICKS_ACROSS_ROAD = 32;
|
||||
const float ROAD_BRICK_SIZE = 0.125f/TREE_SCALE; //(ROAD_WIDTH_METERS / TREE_SCALE) / BRICKS_ACROSS_ROAD; // in voxel units
|
||||
const int ROAD_LENGTH = 1.0f / ROAD_BRICK_SIZE; // in bricks
|
||||
const int ROAD_WIDTH = BRICKS_ACROSS_ROAD; // in bricks
|
||||
glm::vec3 roadPosition(0.5f - (ROAD_BRICK_SIZE * BRICKS_ACROSS_ROAD), 0.0f, 0.0f);
|
||||
const int BRICKS_PER_PACKET = 32; // guessing
|
||||
const int PACKETS_PER_ROAD = VOXELS_PER_PACKET / (ROAD_LENGTH * ROAD_WIDTH);
|
||||
|
||||
void doBuildStreet() {
|
||||
if (roadInitialized) {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
#include <AudioRingBuffer.h>
|
||||
#include <AvatarData.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
|
@ -25,7 +26,8 @@
|
|||
Agent::Agent(const QByteArray& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_voxelEditSender(),
|
||||
_particleEditSender()
|
||||
_particleEditSender(),
|
||||
_avatarAudioStream(NULL)
|
||||
{
|
||||
// be the parent of the script engine so it gets moved when we do
|
||||
_scriptEngine.setParent(this);
|
||||
|
@ -34,6 +36,30 @@ Agent::Agent(const QByteArray& packet) :
|
|||
_scriptEngine.getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
|
||||
}
|
||||
|
||||
Agent::~Agent() {
|
||||
delete _avatarAudioStream;
|
||||
}
|
||||
|
||||
const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * SAMPLE_RATE) / (1000 * 1000)) + 0.5);
|
||||
|
||||
void Agent::setSendAvatarAudioStream(bool sendAvatarAudioStream) {
|
||||
if (sendAvatarAudioStream) {
|
||||
// the agentAudioStream number of samples is related to the ScriptEngine callback rate
|
||||
_avatarAudioStream = new int16_t[SCRIPT_AUDIO_BUFFER_SAMPLES];
|
||||
|
||||
// fill the _audioStream with zeroes to start
|
||||
memset(_avatarAudioStream, 0, SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t));
|
||||
|
||||
_scriptEngine.setNumAvatarAudioBufferSamples(SCRIPT_AUDIO_BUFFER_SAMPLES);
|
||||
_scriptEngine.setAvatarAudioBuffer(_avatarAudioStream);
|
||||
} else {
|
||||
delete _avatarAudioStream;
|
||||
_avatarAudioStream = NULL;
|
||||
|
||||
_scriptEngine.setAvatarAudioBuffer(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void Agent::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
|
|
@ -28,12 +28,17 @@ class Agent : public ThreadedAssignment {
|
|||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool isAvatar READ isAvatar WRITE setIsAvatar)
|
||||
Q_PROPERTY(bool sendAvatarAudioStream READ isSendingAvatarAudioStream WRITE setSendAvatarAudioStream)
|
||||
public:
|
||||
Agent(const QByteArray& packet);
|
||||
~Agent();
|
||||
|
||||
void setIsAvatar(bool isAvatar) { QMetaObject::invokeMethod(&_scriptEngine, "setIsAvatar", Q_ARG(bool, isAvatar)); }
|
||||
bool isAvatar() const { return _scriptEngine.isAvatar(); }
|
||||
|
||||
void setSendAvatarAudioStream(bool sendAvatarAudioStream);
|
||||
bool isSendingAvatarAudioStream() const { return (bool) _scriptEngine.sendsAvatarAudioStream(); }
|
||||
|
||||
public slots:
|
||||
void run();
|
||||
void readPendingDatagrams();
|
||||
|
@ -45,6 +50,8 @@ private:
|
|||
|
||||
ParticleTreeHeadlessViewer _particleViewer;
|
||||
VoxelTreeHeadlessViewer _voxelViewer;
|
||||
|
||||
int16_t* _avatarAudioStream;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__Agent__) */
|
||||
|
|
|
@ -114,7 +114,7 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
|
|||
const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f;
|
||||
|
||||
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
|
||||
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / 90.0f));
|
||||
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / PI_OVER_TWO));
|
||||
|
||||
// multiply the current attenuation coefficient by the calculated off axis coefficient
|
||||
attenuationCoefficient *= offAxisCoefficient;
|
||||
|
@ -148,7 +148,7 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
|
|||
|
||||
// figure out the number of samples of delay and the ratio of the amplitude
|
||||
// in the weak channel for audio spatialization
|
||||
float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource)));
|
||||
float sinRatio = fabsf(sinf(bearingRelativeAngleToSource));
|
||||
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
|
||||
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ MetavoxelServer::MetavoxelServer(const QByteArray& packet) :
|
|||
}
|
||||
|
||||
void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) {
|
||||
edit.apply(_data);
|
||||
edit.apply(_data, SharedObject::getWeakHash());
|
||||
}
|
||||
|
||||
const QString METAVOXEL_SERVER_LOGGING_NAME = "metavoxel-server";
|
||||
|
@ -111,13 +111,17 @@ int MetavoxelSession::parseData(const QByteArray& packet) {
|
|||
}
|
||||
|
||||
void MetavoxelSession::sendDelta() {
|
||||
// wait until we have a valid lod
|
||||
if (!_lod.isValid()) {
|
||||
return;
|
||||
}
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
out << QVariant::fromValue(MetavoxelDeltaMessage());
|
||||
_server->getData().writeDelta(_sendRecords.first().data, out);
|
||||
_server->getData().writeDelta(_sendRecords.first().data, _sendRecords.first().lod, out, _lod);
|
||||
_sequencer.endPacket();
|
||||
|
||||
// record the send
|
||||
SendRecord record = { _sequencer.getOutgoingPacketNumber(), _server->getData() };
|
||||
SendRecord record = { _sequencer.getOutgoingPacketNumber(), _server->getData(), _lod };
|
||||
_sendRecords.append(record);
|
||||
}
|
||||
|
||||
|
@ -139,7 +143,7 @@ void MetavoxelSession::handleMessage(const QVariant& message) {
|
|||
int userType = message.userType();
|
||||
if (userType == ClientStateMessage::Type) {
|
||||
ClientStateMessage state = message.value<ClientStateMessage>();
|
||||
_position = state.position;
|
||||
_lod = state.lod;
|
||||
|
||||
} else if (userType == MetavoxelEditMessage::Type) {
|
||||
_server->applyEdit(message.value<MetavoxelEditMessage>());
|
||||
|
|
|
@ -78,6 +78,7 @@ private:
|
|||
public:
|
||||
int packetNumber;
|
||||
MetavoxelData data;
|
||||
MetavoxelLOD lod;
|
||||
};
|
||||
|
||||
MetavoxelServer* _server;
|
||||
|
@ -86,7 +87,7 @@ private:
|
|||
|
||||
SharedNodePointer _node;
|
||||
|
||||
glm::vec3 _position;
|
||||
MetavoxelLOD _lod;
|
||||
|
||||
QList<SendRecord> _sendRecords;
|
||||
};
|
||||
|
|
|
@ -15,7 +15,14 @@
|
|||
|
||||
OctreeQueryNode::OctreeQueryNode() :
|
||||
_viewSent(false),
|
||||
_octreePacket(new unsigned char[MAX_PACKET_SIZE]),
|
||||
_octreePacketAt(_octreePacket),
|
||||
_octreePacketAvailableBytes(MAX_PACKET_SIZE),
|
||||
_octreePacketWaiting(false),
|
||||
_lastOctreePacket(new unsigned char[MAX_PACKET_SIZE]),
|
||||
_lastOctreePacketLength(0),
|
||||
_duplicatePacketCount(0),
|
||||
_firstSuppressedPacket(usecTimestampNow()),
|
||||
_maxSearchLevel(1),
|
||||
_maxLevelReachedInLastSearch(1),
|
||||
_lastTimeBagEmpty(0),
|
||||
|
@ -27,14 +34,9 @@ OctreeQueryNode::OctreeQueryNode() :
|
|||
_lastClientBoundaryLevelAdjust(0),
|
||||
_lastClientOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
|
||||
_lodChanged(false),
|
||||
_lodInitialized(false)
|
||||
_lodInitialized(false),
|
||||
_sequenceNumber(0)
|
||||
{
|
||||
_octreePacket = new unsigned char[MAX_PACKET_SIZE];
|
||||
_octreePacketAt = _octreePacket;
|
||||
_lastOctreePacket = new unsigned char[MAX_PACKET_SIZE];
|
||||
_lastOctreePacketLength = 0;
|
||||
_duplicatePacketCount = 0;
|
||||
_sequenceNumber = 0;
|
||||
}
|
||||
|
||||
OctreeQueryNode::~OctreeQueryNode() {
|
||||
|
|
|
@ -241,6 +241,9 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue
|
|||
int truePacketsSent = 0;
|
||||
int trueBytesSent = 0;
|
||||
int packetsSentThisInterval = 0;
|
||||
bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) && nodeData->getViewFrustumJustStoppedChanging())
|
||||
|| nodeData->hasLodChanged();
|
||||
|
||||
bool somethingToSend = true; // assume we have something
|
||||
|
||||
// FOR NOW... node tells us if it wants to receive only view frustum deltas
|
||||
|
@ -365,10 +368,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue
|
|||
<< " Wasted:" << _totalWastedBytes;
|
||||
}
|
||||
|
||||
// start tracking our stats
|
||||
bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta())
|
||||
&& nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged();
|
||||
|
||||
// If we're starting a full scene, then definitely we want to empty the nodeBag
|
||||
if (isFullScene) {
|
||||
nodeData->nodeBag.deleteAll();
|
||||
|
@ -382,6 +381,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue
|
|||
}
|
||||
|
||||
::startSceneSleepTime = _usleepTime;
|
||||
// start tracking our stats
|
||||
nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getOctree()->getRoot(), _myServer->getJurisdiction());
|
||||
|
||||
// This is the start of "resending" the scene.
|
||||
|
@ -432,10 +432,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue
|
|||
int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving()
|
||||
? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
|
||||
|
||||
|
||||
bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) &&
|
||||
nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged();
|
||||
|
||||
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor,
|
||||
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
|
||||
wantOcclusionCulling, coverageMap, boundaryLevelAdjust, voxelSizeScale,
|
||||
|
|
|
@ -19,14 +19,8 @@ else ()
|
|||
set(WIN_GLEW_SEARCH_DIRS "${GLEW_ROOT_DIR}" "$ENV{GLEW_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/glew")
|
||||
|
||||
find_path(GLEW_INCLUDE_DIRS GL/glew.h PATH_SUFFIXES include HINTS ${WIN_GLEW_SEARCH_DIRS})
|
||||
|
||||
if (CMAKE_CL_64)
|
||||
set(WIN_ARCH_DIR "x64")
|
||||
else()
|
||||
set(WIN_ARCH_DIR "Win32")
|
||||
endif()
|
||||
|
||||
find_library(GLEW_LIBRARY glew32s PATH_SUFFIXES "lib/Release/${WIN_ARCH_DIR}" HINTS ${WIN_GLEW_SEARCH_DIRS})
|
||||
|
||||
find_library(GLEW_LIBRARY glew32s PATH_SUFFIXES "lib/Release/Win32" HINTS ${WIN_GLEW_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
|
|
@ -17,12 +17,8 @@ else ()
|
|||
if (WIN32)
|
||||
set(WIN_GLUT_SEARCH_DIRS "${GLUT_ROOT_DIR}" "$ENV{GLUT_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/freeglut" "${OPENGL_INCLUDE_DIR}")
|
||||
find_path(GLUT_INCLUDE_DIR GL/glut.h PATH_SUFFIXES include HINTS ${WIN_GLUT_SEARCH_DIRS})
|
||||
|
||||
if (CMAKE_CL_64)
|
||||
set(WIN_ARCH_DIR "x64")
|
||||
endif()
|
||||
|
||||
find_library(GLUT_glut_LIBRARY freeglut PATH_SUFFIXES lib/${WIN_ARCH_DIR} HINTS ${WIN_GLUT_SEARCH_DIRS})
|
||||
|
||||
find_library(GLUT_glut_LIBRARY freeglut PATH_SUFFIXES lib HINTS ${WIN_GLUT_SEARCH_DIRS})
|
||||
else ()
|
||||
find_path(GLUT_INCLUDE_DIR GL/glut.h
|
||||
"${GLUT_LOCATION}/include"
|
||||
|
|
|
@ -36,26 +36,14 @@ else (LIBOVR_LIBRARIES AND LIBOVR_INCLUDE_DIRS)
|
|||
if (UDEV_LIBRARY AND XINERAMA_LIBRARY AND OVR_LIBRARY)
|
||||
set(LIBOVR_LIBRARIES "${OVR_LIBRARY};${UDEV_LIBRARY};${XINERAMA_LIBRARY}" CACHE INTERNAL "Oculus libraries")
|
||||
endif (UDEV_LIBRARY AND XINERAMA_LIBRARY AND OVR_LIBRARY)
|
||||
elseif (WIN32)
|
||||
if (CMAKE_CL_64)
|
||||
set(WINDOWS_ARCH_DIR "Win32")
|
||||
|
||||
if (CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
set(WINDOWS_LIBOVR_NAME "libovrd.lib")
|
||||
else()
|
||||
set(WINDOWS_LIBOVR_NAME "libovr.lib")
|
||||
endif()
|
||||
elseif (WIN32)
|
||||
if (CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
set(WINDOWS_LIBOVR_NAME "libovrd.lib")
|
||||
else()
|
||||
set(WINDOWS_ARCH_DIR "x64")
|
||||
|
||||
if (CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
set(WINDOWS_LIBOVR_NAME "libovr64d.lib")
|
||||
else()
|
||||
set(WINDOWS_LIBOVR_NAME "libovr64.lib")
|
||||
endif()
|
||||
set(WINDOWS_LIBOVR_NAME "libovr.lib")
|
||||
endif()
|
||||
|
||||
find_library(LIBOVR_LIBRARIES "Lib/${WINDOWS_ARCH_DIR}/${LIBOVR_NAME}" HINTS ${LIBOVR_SEARCH_DIRS})
|
||||
find_library(LIBOVR_LIBRARIES "Lib/Win32/${LIBOVR_NAME}" HINTS ${LIBOVR_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
||||
if (LIBOVR_INCLUDE_DIRS AND LIBOVR_LIBRARIES)
|
||||
|
|
114
cmake/modules/FindQt5LinguistToolsMacros.cmake
Normal file
114
cmake/modules/FindQt5LinguistToolsMacros.cmake
Normal file
|
@ -0,0 +1,114 @@
|
|||
#=============================================================================
|
||||
# Copyright 2005-2011 Kitware, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# * Neither the name of Kitware, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#=============================================================================
|
||||
|
||||
|
||||
|
||||
function(QT5_CREATE_TRANSLATION_CUSTOM _qm_files)
|
||||
set(options)
|
||||
set(oneValueArgs)
|
||||
set(multiValueArgs OPTIONS)
|
||||
|
||||
cmake_parse_arguments(_LUPDATE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
set(_lupdate_files ${_LUPDATE_UNPARSED_ARGUMENTS})
|
||||
set(_lupdate_options ${_LUPDATE_OPTIONS})
|
||||
|
||||
set(_my_sources)
|
||||
set(_my_tsfiles)
|
||||
foreach(_file ${_lupdate_files})
|
||||
get_filename_component(_ext ${_file} EXT)
|
||||
get_filename_component(_abs_FILE ${_file} ABSOLUTE)
|
||||
if(_ext MATCHES "ts")
|
||||
list(APPEND _my_tsfiles ${_abs_FILE})
|
||||
else()
|
||||
list(APPEND _my_sources ${_abs_FILE})
|
||||
endif()
|
||||
endforeach()
|
||||
set(_my_temptsfiles)
|
||||
foreach(_ts_file ${_my_tsfiles})
|
||||
if(_my_sources)
|
||||
# make a list file to call lupdate on, so we don't make our commands too
|
||||
# long for some systems
|
||||
get_filename_component(_ts_name ${_ts_file} NAME_WE)
|
||||
set(_ts_lst_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_ts_name}_lst_file")
|
||||
set(_lst_file_srcs)
|
||||
foreach(_lst_file_src ${_my_sources})
|
||||
set(_lst_file_srcs "${_lst_file_src}\n${_lst_file_srcs}")
|
||||
endforeach()
|
||||
|
||||
get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES)
|
||||
foreach(_pro_include ${_inc_DIRS})
|
||||
get_filename_component(_abs_include "${_pro_include}" ABSOLUTE)
|
||||
set(_lst_file_srcs "-I${_pro_include}\n${_lst_file_srcs}")
|
||||
endforeach()
|
||||
|
||||
file(WRITE ${_ts_lst_file} "${_lst_file_srcs}")
|
||||
endif()
|
||||
get_filename_component(_ts_nm ${_ts_file} NAME)
|
||||
set(_tmpts_file "${CMAKE_CURRENT_BINARY_DIR}/${_ts_nm}")
|
||||
list(APPEND _my_temptsfiles ${_tmpts_file})
|
||||
get_source_file_property(_qm_output_location ${_ts_file} OUTPUT_LOCATION)
|
||||
add_custom_command(
|
||||
OUTPUT ${_tmpts_file}
|
||||
COMMAND ${Qt5_LUPDATE_EXECUTABLE}
|
||||
ARGS ${_lupdate_options} "@${_ts_lst_file}" -ts ${_ts_file}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${_ts_file} ${_tmpts_file}
|
||||
DEPENDS ${_my_sources} ${_ts_lst_file} VERBATIM)
|
||||
if( _qm_output_location )
|
||||
set_property(SOURCE ${_tmpts_file} PROPERTY OUTPUT_LOCATION ${_qm_output_location})
|
||||
endif()
|
||||
endforeach()
|
||||
qt5_add_translation(${_qm_files} ${_my_temptsfiles})
|
||||
set(${_qm_files} ${${_qm_files}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(QT5_ADD_TRANSLATION _qm_files)
|
||||
foreach(_current_FILE ${ARGN})
|
||||
get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
|
||||
get_filename_component(qm ${_abs_FILE} NAME_WE)
|
||||
get_source_file_property(output_location ${_abs_FILE} OUTPUT_LOCATION)
|
||||
if(output_location)
|
||||
file(MAKE_DIRECTORY "${output_location}")
|
||||
set(qm "${output_location}/${qm}.qm")
|
||||
else()
|
||||
set(qm "${CMAKE_CURRENT_BINARY_DIR}/${qm}.qm")
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT ${qm}
|
||||
COMMAND ${Qt5_LRELEASE_EXECUTABLE}
|
||||
ARGS ${_abs_FILE} -qm ${qm}
|
||||
DEPENDS ${_abs_FILE} VERBATIM
|
||||
)
|
||||
list(APPEND ${_qm_files} ${qm})
|
||||
endforeach()
|
||||
set(${_qm_files} ${${_qm_files}} PARENT_SCOPE)
|
||||
endfunction()
|
38
cmake/modules/FindQxmpp.cmake
Normal file
38
cmake/modules/FindQxmpp.cmake
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Try to find the qxmpp library
|
||||
#
|
||||
# You can provide a QXMPP_ROOT_DIR which contains lib and include directories
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# QXMPP_FOUND - system found qxmpp
|
||||
# QXMPP_INCLUDE_DIRS - the qxmpp include directory
|
||||
# QXMPP_LIBRARIES - Link this to use qxmpp
|
||||
#
|
||||
# Created on 3/10/2014 by Stephen Birarda
|
||||
# Copyright (c) 2014 High Fidelity
|
||||
#
|
||||
|
||||
if (QXMPP_LIBRARIES AND QXMPP_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(QXMPP_FOUND TRUE)
|
||||
else ()
|
||||
|
||||
set(QXMPP_SEARCH_DIRS "${QXMPP_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/qxmpp")
|
||||
|
||||
find_path(QXMPP_INCLUDE_DIR QXmppClient.h PATH_SUFFIXES include/qxmpp HINTS ${QXMPP_SEARCH_DIRS})
|
||||
|
||||
find_library(QXMPP_LIBRARY NAMES qxmpp qxmpp0 qxmpp_d PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(QXMPP DEFAULT_MSG QXMPP_INCLUDE_DIR QXMPP_LIBRARY)
|
||||
|
||||
if (QXMPP_FOUND)
|
||||
if (NOT QXMPP_FIND_QUIETLY)
|
||||
message(STATUS "Found qxmpp: ${QXMPP_LIBRARY}")
|
||||
endif ()
|
||||
else ()
|
||||
if (QXMPP_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find qxmpp")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
|
@ -359,8 +359,6 @@ void DomainServer::addNodeToNodeListAndConfirmConnection(const QByteArray& packe
|
|||
sendDomainListToNode(newNode, senderSockAddr, nodeInterestListFromPacket(packet, numPreInterestBytes));
|
||||
}
|
||||
|
||||
const int NUM_BYTES_DATA_SERVER_REGISTRATION_TOKEN = 16;
|
||||
|
||||
int DomainServer::parseNodeDataFromByteArray(NodeType_t& nodeType, HifiSockAddr& publicSockAddr,
|
||||
HifiSockAddr& localSockAddr, const QByteArray& packet,
|
||||
const HifiSockAddr& senderSockAddr) {
|
||||
|
@ -546,8 +544,16 @@ void DomainServer::readAvailableDatagrams() {
|
|||
// construct the requested assignment from the packet data
|
||||
Assignment requestAssignment(receivedPacket);
|
||||
|
||||
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
// Suppress these for Assignment::AgentType to once per 5 seconds
|
||||
static quint64 lastNoisyMessage = usecTimestampNow();
|
||||
quint64 timeNow = usecTimestampNow();
|
||||
const quint64 NOISY_TIME_ELAPSED = 5 * USECS_PER_SECOND;
|
||||
bool noisyMessage = false;
|
||||
if (requestAssignment.getType() != Assignment::AgentType || (timeNow - lastNoisyMessage) > NOISY_TIME_ELAPSED) {
|
||||
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessage = true;
|
||||
}
|
||||
|
||||
SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
|
||||
|
||||
|
@ -564,8 +570,15 @@ void DomainServer::readAvailableDatagrams() {
|
|||
nodeList->getNodeSocket().writeDatagram(assignmentPacket,
|
||||
senderSockAddr.getAddress(), senderSockAddr.getPort());
|
||||
} else {
|
||||
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
if (requestAssignment.getType() != Assignment::AgentType || (timeNow - lastNoisyMessage) > NOISY_TIME_ELAPSED) {
|
||||
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessage = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (noisyMessage) {
|
||||
lastNoisyMessage = timeNow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,10 @@ var PIXELS_PER_EXTRUDE_VOXEL = 16;
|
|||
var WHEEL_PIXELS_PER_SCALE_CHANGE = 100;
|
||||
var MAX_VOXEL_SCALE = 1.0;
|
||||
var MIN_VOXEL_SCALE = 1.0 / Math.pow(2.0, 8.0);
|
||||
var WHITE_COLOR = { red: 255, green: 255, blue: 255 };
|
||||
|
||||
var MAX_PASTE_VOXEL_SCALE = 256;
|
||||
var MIN_PASTE_VOXEL_SCALE = .256;
|
||||
|
||||
var zFightingSizeAdjust = 0.002; // used to adjust preview voxels to prevent z fighting
|
||||
var previewLineWidth = 1.5;
|
||||
|
@ -199,6 +203,8 @@ var voxelToolAt = 0;
|
|||
var recolorToolAt = 1;
|
||||
var eyedropperToolAt = 2;
|
||||
|
||||
var pasteModeColor = { red: 132, green: 61, blue: 255 };
|
||||
|
||||
var voxelTool = Overlays.addOverlay("image", {
|
||||
x: 0, y: 0, width: toolWidth, height: toolHeight,
|
||||
subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight },
|
||||
|
@ -262,7 +268,7 @@ var thumb = Overlays.addOverlay("image", {
|
|||
visible: false
|
||||
});
|
||||
|
||||
var pointerVoxelScale = 0; // this is the voxel scale used for click to add or delete
|
||||
var pointerVoxelScale = Math.floor(MAX_VOXEL_SCALE + MIN_VOXEL_SCALE) / 2; // this is the voxel scale used for click to add or delete
|
||||
var pointerVoxelScaleSet = false; // if voxel scale has not yet been set, we use the intersection size
|
||||
|
||||
var pointerVoxelScaleSteps = 8; // the number of slider position steps
|
||||
|
@ -271,6 +277,106 @@ var pointerVoxelScaleMin = Math.pow(2, (1-pointerVoxelScaleOriginStep));
|
|||
var pointerVoxelScaleMax = Math.pow(2, (pointerVoxelScaleSteps-pointerVoxelScaleOriginStep));
|
||||
var thumbDeltaPerStep = thumbExtents / (pointerVoxelScaleSteps - 1);
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////// IMPORT MODULE ///////////////////////////////
|
||||
// Move the following code to a separate file when include will be available.
|
||||
var importTree;
|
||||
var importPreview;
|
||||
var importBoundaries;
|
||||
var isImporting;
|
||||
var importPosition;
|
||||
var importScale;
|
||||
|
||||
function initImport() {
|
||||
importPreview = Overlays.addOverlay("localvoxels", {
|
||||
name: "import",
|
||||
position: { x: 0, y: 0, z: 0},
|
||||
scale: 1,
|
||||
visible: false
|
||||
});
|
||||
importBoundaries = Overlays.addOverlay("cube", {
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
scale: 1,
|
||||
color: { red: 128, blue: 128, green: 128 },
|
||||
solid: false,
|
||||
visible: false
|
||||
})
|
||||
isImporting = false;
|
||||
importPosition = { x: 0, y: 0, z: 0 };
|
||||
importScale = 0;
|
||||
}
|
||||
|
||||
function importVoxels() {
|
||||
if (Clipboard.importVoxels()) {
|
||||
isImporting = true;
|
||||
if (importScale <= 0) {
|
||||
importScale = 1;
|
||||
}
|
||||
} else {
|
||||
isImporting = false;
|
||||
}
|
||||
|
||||
return isImporting;
|
||||
}
|
||||
|
||||
function moveImport(position) {
|
||||
if (0 < position.x && 0 < position.y && 0 < position.z) {
|
||||
importPosition = position;
|
||||
Overlays.editOverlay(importPreview, {
|
||||
position: { x: importPosition.x, y: importPosition.y, z: importPosition.z }
|
||||
});
|
||||
Overlays.editOverlay(importBoundaries, {
|
||||
position: { x: importPosition.x, y: importPosition.y, z: importPosition.z }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function rescaleImport(scale) {
|
||||
if (0 < scale) {
|
||||
importScale = scale;
|
||||
Overlays.editOverlay(importPreview, {
|
||||
scale: importScale
|
||||
});
|
||||
Overlays.editOverlay(importBoundaries, {
|
||||
scale: importScale
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showImport(doShow) {
|
||||
Overlays.editOverlay(importPreview, {
|
||||
visible: doShow
|
||||
});
|
||||
Overlays.editOverlay(importBoundaries, {
|
||||
visible: doShow
|
||||
});
|
||||
}
|
||||
|
||||
function placeImport() {
|
||||
if (isImporting) {
|
||||
Clipboard.pasteVoxel(importPosition.x, importPosition.y, importPosition.z, importScale);
|
||||
isImporting = false;
|
||||
}
|
||||
}
|
||||
|
||||
function cancelImport() {
|
||||
if (isImporting) {
|
||||
isImporting = false;
|
||||
showImport(false);
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupImport() {
|
||||
Overlays.deleteOverlay(importPreview);
|
||||
Overlays.deleteOverlay(importBoundaries);
|
||||
isImporting = false;
|
||||
importPostion = { x: 0, y: 0, z: 0 };
|
||||
importScale = 0;
|
||||
}
|
||||
/////////////////////////////////// END IMPORT MODULE /////////////////////////////
|
||||
initImport();
|
||||
|
||||
if (editToolsOn) {
|
||||
moveTools();
|
||||
}
|
||||
|
@ -295,6 +401,13 @@ function calcScaleFromThumb(newThumbX) {
|
|||
thumbAt = newThumbX - minThumbX;
|
||||
thumbStep = Math.floor((thumbAt/ thumbExtents) * (pointerVoxelScaleSteps-1)) + 1;
|
||||
pointerVoxelScale = Math.pow(2, (thumbStep-pointerVoxelScaleOriginStep));
|
||||
|
||||
// if importing, rescale import ...
|
||||
if (isImporting) {
|
||||
var importScale = (pointerVoxelScale / MAX_VOXEL_SCALE) * MAX_PASTE_VOXEL_SCALE;
|
||||
rescaleImport(importScale);
|
||||
}
|
||||
|
||||
// now reset the display accordingly...
|
||||
calcThumbFromScale(pointerVoxelScale);
|
||||
|
||||
|
@ -308,7 +421,23 @@ function setAudioPosition() {
|
|||
audioOptions.position = Vec3.sum(camera, forwardVector);
|
||||
}
|
||||
|
||||
function getNewVoxelPosition() {
|
||||
function getNewPasteVoxel(pickRay) {
|
||||
|
||||
var voxelSize = MIN_PASTE_VOXEL_SCALE + (MAX_PASTE_VOXEL_SCALE - MIN_PASTE_VOXEL_SCALE) * pointerVoxelScale - 1;
|
||||
var origin = { x: pickRay.direction.x, y: pickRay.direction.y, z: pickRay.direction.z };
|
||||
|
||||
origin.x += pickRay.origin.x;
|
||||
origin.y += pickRay.origin.y;
|
||||
origin.z += pickRay.origin.z;
|
||||
|
||||
origin.x -= voxelSize / 2;
|
||||
origin.y -= voxelSize / 2;
|
||||
origin.z += voxelSize / 2;
|
||||
|
||||
return {origin: origin, voxelSize: voxelSize};
|
||||
}
|
||||
|
||||
function getNewVoxelPosition() {
|
||||
var camera = Camera.getPosition();
|
||||
var forwardVector = Quat.getFront(MyAvatar.orientation);
|
||||
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, NEW_VOXEL_DISTANCE_FROM_CAMERA));
|
||||
|
@ -337,6 +466,7 @@ var trackAsOrbitOrPan = false;
|
|||
var voxelToolSelected = true;
|
||||
var recolorToolSelected = false;
|
||||
var eyedropperToolSelected = false;
|
||||
var pasteMode = false;
|
||||
|
||||
function playRandomAddSound(audioOptions) {
|
||||
if (Math.random() < 0.33) {
|
||||
|
@ -523,6 +653,38 @@ function showPreviewVoxel() {
|
|||
function showPreviewLines() {
|
||||
|
||||
var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY);
|
||||
|
||||
if (pasteMode) { // free voxel pasting
|
||||
|
||||
Overlays.editOverlay(voxelPreview, { visible: false });
|
||||
Overlays.editOverlay(linePreviewLeft, { visible: false });
|
||||
|
||||
var pasteVoxel = getNewPasteVoxel(pickRay);
|
||||
|
||||
// X axis
|
||||
Overlays.editOverlay(linePreviewBottom, {
|
||||
position: pasteVoxel.origin,
|
||||
end: {x: pasteVoxel.origin.x + pasteVoxel.voxelSize, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z },
|
||||
visible: true
|
||||
});
|
||||
|
||||
// Y axis
|
||||
Overlays.editOverlay(linePreviewRight, {
|
||||
position: pasteVoxel.origin,
|
||||
end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y + pasteVoxel.voxelSize, z: pasteVoxel.origin.z },
|
||||
visible: true
|
||||
});
|
||||
|
||||
// Z axis
|
||||
Overlays.editOverlay(linePreviewTop, {
|
||||
position: pasteVoxel.origin,
|
||||
end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z - pasteVoxel.voxelSize },
|
||||
visible: true
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
|
||||
if (intersection.intersects) {
|
||||
|
@ -617,6 +779,8 @@ function trackKeyReleaseEvent(event) {
|
|||
if (editToolsOn) {
|
||||
if (event.text == "ESC") {
|
||||
pointerVoxelScaleSet = false;
|
||||
pasteMode = false;
|
||||
moveTools();
|
||||
}
|
||||
if (event.text == "-") {
|
||||
thumbX -= thumbDeltaPerStep;
|
||||
|
@ -821,6 +985,23 @@ function mousePressEvent(event) {
|
|||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction);
|
||||
|
||||
if (isImporting) {
|
||||
print("placing import...");
|
||||
placeImport();
|
||||
showImport(false);
|
||||
moveTools();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pasteMode) {
|
||||
var pasteVoxel = getNewPasteVoxel(pickRay);
|
||||
Clipboard.pasteVoxel(pasteVoxel.origin.x, pasteVoxel.origin.y, pasteVoxel.origin.z, pasteVoxel.voxelSize);
|
||||
pasteMode = false;
|
||||
moveTools();
|
||||
return;
|
||||
}
|
||||
|
||||
if (intersection.intersects) {
|
||||
// if the user hasn't updated the
|
||||
if (!pointerVoxelScaleSet) {
|
||||
|
@ -927,13 +1108,6 @@ function keyPressEvent(event) {
|
|||
}
|
||||
}
|
||||
|
||||
// do this even if not in edit tools
|
||||
if (event.text == " ") {
|
||||
// Reset my orientation!
|
||||
var orientation = { x:0, y:0, z:0, w:1 };
|
||||
Camera.setOrientation(orientation);
|
||||
MyAvatar.orientation = orientation;
|
||||
}
|
||||
trackKeyPressEvent(event); // used by preview support
|
||||
}
|
||||
|
||||
|
@ -974,25 +1148,42 @@ function cleanupMenus() {
|
|||
function menuItemEvent(menuItem) {
|
||||
|
||||
// handle clipboard items
|
||||
if (selectToolSelected) {
|
||||
if (editToolsOn) {
|
||||
|
||||
var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY);
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
selectedVoxel = calculateVoxelFromIntersection(intersection,"select");
|
||||
if (menuItem == "Copy") {
|
||||
print("copying...");
|
||||
Clipboard.copyVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
pasteMode = true;
|
||||
moveTools();
|
||||
}
|
||||
if (menuItem == "Cut") {
|
||||
print("cutting...");
|
||||
Clipboard.cutVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
pasteMode = true;
|
||||
moveTools();
|
||||
}
|
||||
if (menuItem == "Paste") {
|
||||
print("pasting...");
|
||||
Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
if (isImporting) {
|
||||
print("placing import...");
|
||||
placeImport();
|
||||
showImport(false);
|
||||
} else {
|
||||
print("pasting...");
|
||||
Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
}
|
||||
pasteMode = false;
|
||||
moveTools();
|
||||
}
|
||||
if (menuItem == "Delete") {
|
||||
print("deleting...");
|
||||
Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
if (isImporting) {
|
||||
cancelImport();
|
||||
} else {
|
||||
Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
}
|
||||
}
|
||||
|
||||
if (menuItem == "Export Voxels") {
|
||||
|
@ -1000,8 +1191,11 @@ function menuItemEvent(menuItem) {
|
|||
Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
}
|
||||
if (menuItem == "Import Voxels") {
|
||||
print("import");
|
||||
Clipboard.importVoxels();
|
||||
print("importing...");
|
||||
if (importVoxels()) {
|
||||
showImport(true);
|
||||
}
|
||||
moveTools();
|
||||
}
|
||||
if (menuItem == "Nudge") {
|
||||
print("nudge");
|
||||
|
@ -1156,19 +1350,23 @@ function moveTools() {
|
|||
recolorToolOffset = 1,
|
||||
eyedropperToolOffset = 1;
|
||||
|
||||
if (trackAsRecolor || recolorToolSelected) {
|
||||
var voxelToolColor = WHITE_COLOR;
|
||||
|
||||
if (recolorToolSelected) {
|
||||
recolorToolOffset = 2;
|
||||
} else if (trackAsEyedropper || eyedropperToolSelected) {
|
||||
} else if (eyedropperToolSelected) {
|
||||
eyedropperToolOffset = 2;
|
||||
} else if (trackAsOrbitOrPan) {
|
||||
// nothing gets selected in this case...
|
||||
} else {
|
||||
if (pasteMode) {
|
||||
voxelToolColor = pasteModeColor;
|
||||
}
|
||||
voxelToolOffset = 2;
|
||||
}
|
||||
|
||||
Overlays.editOverlay(voxelTool, {
|
||||
subImage: { x: 0, y: toolHeight * voxelToolOffset, width: toolWidth, height: toolHeight },
|
||||
x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * voxelToolAt), width: toolWidth, height: toolHeight,
|
||||
color: voxelToolColor,
|
||||
visible: editToolsOn
|
||||
});
|
||||
|
||||
|
@ -1330,14 +1528,27 @@ function checkControllers() {
|
|||
}
|
||||
|
||||
function update(deltaTime) {
|
||||
var newWindowDimensions = Controller.getViewportDimensions();
|
||||
if (newWindowDimensions.x != windowDimensions.x || newWindowDimensions.y != windowDimensions.y) {
|
||||
windowDimensions = newWindowDimensions;
|
||||
moveTools();
|
||||
}
|
||||
|
||||
if (editToolsOn) {
|
||||
var newWindowDimensions = Controller.getViewportDimensions();
|
||||
if (newWindowDimensions.x != windowDimensions.x || newWindowDimensions.y != windowDimensions.y) {
|
||||
windowDimensions = newWindowDimensions;
|
||||
moveTools();
|
||||
}
|
||||
|
||||
checkControllers();
|
||||
|
||||
// Move Import Preview
|
||||
if (isImporting) {
|
||||
var position = MyAvatar.position;
|
||||
var forwardVector = Quat.getFront(MyAvatar.orientation);
|
||||
var targetPosition = Vec3.sum(position, Vec3.multiply(forwardVector, importScale));
|
||||
var newPosition = {
|
||||
x: Math.floor(targetPosition.x / importScale) * importScale,
|
||||
y: Math.floor(targetPosition.y / importScale) * importScale,
|
||||
z: Math.floor(targetPosition.z / importScale) * importScale
|
||||
}
|
||||
moveImport(newPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1363,6 +1574,11 @@ function wheelEvent(event) {
|
|||
calcThumbFromScale(pointerVoxelScale);
|
||||
trackMouseEvent(event);
|
||||
wheelPixelsMoved = 0;
|
||||
|
||||
if (isImporting) {
|
||||
var importScale = (pointerVoxelScale / MAX_VOXEL_SCALE) * MAX_PASTE_VOXEL_SCALE;
|
||||
rescaleImport(importScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1395,6 +1611,7 @@ function scriptEnding() {
|
|||
Overlays.deleteOverlay(thumb);
|
||||
Controller.releaseKeyEvents({ text: "+" });
|
||||
Controller.releaseKeyEvents({ text: "-" });
|
||||
cleanupImport();
|
||||
cleanupMenus();
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
|
|
@ -17,6 +17,9 @@ set(LIBOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/oculus")
|
|||
set(SIXENSE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/Sixense")
|
||||
set(VISAGE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/visage")
|
||||
|
||||
find_package(Qt5LinguistTools REQUIRED)
|
||||
find_package(Qt5LinguistToolsMacros)
|
||||
|
||||
if (DEFINED ENV{JOB_ID})
|
||||
set(BUILD_SEQ $ENV{JOB_ID})
|
||||
else ()
|
||||
|
@ -32,7 +35,7 @@ elseif (WIN32)
|
|||
add_definitions( -D_USE_MATH_DEFINES ) # apparently needed to get M_PI and other defines from cmath/math.h
|
||||
add_definitions( -DWINDOWS_LEAN_AND_MEAN ) # needed to make sure windows doesn't go to crazy with its defines
|
||||
|
||||
set(GL_HEADERS "#define GLEW_STATIC\n#include <windowshacks.h>\n#include <GL/glew.h>\n#include <GL/glut.h>")
|
||||
set(GL_HEADERS "#include <windowshacks.h>\n#include <GL/glew.h>\n#include <GL/glut.h>")
|
||||
endif ()
|
||||
|
||||
# set up the external glm library
|
||||
|
@ -70,8 +73,17 @@ file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
|
|||
# have qt5 wrap them and generate the appropriate header files
|
||||
qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}")
|
||||
|
||||
# grab the resource files in resources
|
||||
file (GLOB_RECURSE QT_RESOURCE_FILES resources/*.qrc)
|
||||
# have qt5 wrap them and generate the appropriate source files
|
||||
qt5_add_resources(QT_RESOURCES "${QT_RESOURCE_FILES}")
|
||||
|
||||
# add them to the interface source files
|
||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}")
|
||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}")
|
||||
|
||||
set(QM ${TARGET_NAME}_en.qm)
|
||||
set(TS ${TARGET_NAME}_en.ts)
|
||||
qt5_create_translation_custom(${QM} ${INTERFACE_SRCS} ${QT_UI_FILES} ${TS})
|
||||
|
||||
if (APPLE)
|
||||
# configure CMake to use a custom Info.plist
|
||||
|
@ -101,7 +113,7 @@ if (APPLE)
|
|||
endif()
|
||||
|
||||
# create the executable, make it a bundle on OS X
|
||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS})
|
||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
|
||||
|
||||
# link in the hifi shared library
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
|
@ -122,6 +134,7 @@ find_package(LibOVR)
|
|||
find_package(Sixense)
|
||||
find_package(Visage)
|
||||
find_package(ZLIB)
|
||||
find_package(Qxmpp)
|
||||
|
||||
# include the Sixense library for Razer Hydra if available
|
||||
if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE)
|
||||
|
@ -139,7 +152,8 @@ if (VISAGE_FOUND AND NOT DISABLE_VISAGE)
|
|||
include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
|
||||
if (APPLE)
|
||||
add_definitions(-DMAC_OS_X)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment -isystem ${VISAGE_INCLUDE_DIRS}")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment")
|
||||
include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
|
||||
find_library(AVFoundation AVFoundation)
|
||||
find_library(CoreMedia CoreMedia)
|
||||
find_library(NEW_STD_LIBRARY libc++.dylib /usr/lib/)
|
||||
|
@ -160,6 +174,14 @@ if (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
|||
target_link_libraries(${TARGET_NAME} "${LIBOVR_LIBRARIES}")
|
||||
endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
||||
|
||||
# and with qxmpp for chat
|
||||
if (QXMPP_FOUND AND NOT DISABLE_QXMPP)
|
||||
add_definitions(-DHAVE_QXMPP -DQXMPP_STATIC)
|
||||
include_directories(SYSTEM ${QXMPP_INCLUDE_DIR})
|
||||
|
||||
target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}")
|
||||
endif (QXMPP_FOUND AND NOT DISABLE_QXMPP)
|
||||
|
||||
# include headers for interface and InterfaceConfig.
|
||||
include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes")
|
||||
|
||||
|
|
4
interface/external/visage/readme.txt
vendored
4
interface/external/visage/readme.txt
vendored
|
@ -5,8 +5,8 @@ Andrzej Kapolka, February 11, 2014
|
|||
1. Copy the Visage sdk folders (lib, include, dependencies) into the interface/external/visage folder.
|
||||
This readme.txt should be there as well.
|
||||
|
||||
2. Copy the Visage configuration data folder (visageSDK-MacOS/Samples/MacOSX/data/) to interface/resources/visage
|
||||
(i.e., so that interface/resources/visage/candide3.wfm is accessible)
|
||||
2. Copy the contents of the Visage configuration data folder (visageSDK-MacOS/Samples/MacOSX/data/) to
|
||||
interface/resources/visage (i.e., so that interface/resources/visage/candide3.wfm is accessible)
|
||||
|
||||
3. Copy the Visage license file to interface/resources/visage/license.vlc.
|
||||
|
||||
|
|
161
interface/interface_en.ts
Normal file
161
interface/interface_en.ts
Normal file
|
@ -0,0 +1,161 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>Application</name>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="1354"/>
|
||||
<source>Export Voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="1355"/>
|
||||
<source>Sparse Voxel Octree Files (*.svo)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="3554"/>
|
||||
<source>Open Script</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="3555"/>
|
||||
<source>JavaScript Files (*.js)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatWindow</name>
|
||||
<message>
|
||||
<location filename="ui/chatWindow.ui" line="14"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="141"/>
|
||||
<source>Chat</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/chatWindow.ui" line="41"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="142"/>
|
||||
<source>Connecting to XMPP...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/chatWindow.ui" line="62"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="143"/>
|
||||
<source> online now:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="src/ui/ChatWindow.cpp" line="115"/>
|
||||
<source>day</source>
|
||||
<translation>
|
||||
<numerusform>%n day</numerusform>
|
||||
<numerusform>%n days</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="src/ui/ChatWindow.cpp" line="115"/>
|
||||
<source>hour</source>
|
||||
<translation>
|
||||
<numerusform>%n hour</numerusform>
|
||||
<numerusform>%n hours</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="src/ui/ChatWindow.cpp" line="115"/>
|
||||
<source>minute</source>
|
||||
<translation>
|
||||
<numerusform>%n minute</numerusform>
|
||||
<numerusform>%n minutes</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>second</source>
|
||||
<translation type="vanished">
|
||||
<numerusform>%n second</numerusform>
|
||||
<numerusform>%n seconds</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ChatWindow.cpp" line="170"/>
|
||||
<source>%1 online now:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Dialog</name>
|
||||
<message>
|
||||
<location filename="ui/updateDialog.ui" line="20"/>
|
||||
<location filename="ui/updateDialog.ui" line="73"/>
|
||||
<location filename="../build/interface/ui_updateDialog.h" line="137"/>
|
||||
<location filename="../build/interface/ui_updateDialog.h" line="138"/>
|
||||
<source>Update Required</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/updateDialog.ui" line="129"/>
|
||||
<location filename="../build/interface/ui_updateDialog.h" line="140"/>
|
||||
<source>Download</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/updateDialog.ui" line="151"/>
|
||||
<location filename="../build/interface/ui_updateDialog.h" line="141"/>
|
||||
<source>Skip Version</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/updateDialog.ui" line="173"/>
|
||||
<location filename="../build/interface/ui_updateDialog.h" line="142"/>
|
||||
<source>Close</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Menu</name>
|
||||
<message>
|
||||
<location filename="src/Menu.cpp" line="422"/>
|
||||
<source>Open .ini config file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Menu.cpp" line="424"/>
|
||||
<location filename="src/Menu.cpp" line="436"/>
|
||||
<source>Text files (*.ini)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Menu.cpp" line="434"/>
|
||||
<source>Save .ini config file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
<message>
|
||||
<location filename="src/ImportDialog.cpp" line="22"/>
|
||||
<location filename="src/ImportDialog.cpp" line="23"/>
|
||||
<source>Import Voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ImportDialog.cpp" line="24"/>
|
||||
<source>Loading ...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ImportDialog.cpp" line="25"/>
|
||||
<source>Place voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ImportDialog.cpp" line="26"/>
|
||||
<source><b>Import</b> %1 as voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ImportDialog.cpp" line="27"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
14
interface/resources/images/close.svg
Normal file
14
interface/resources/images/close.svg
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 15.9 15.9" enable-background="new 0 0 15.9 15.9" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#666666" d="M15.5,13.7l-1.8,1.8c-0.2,0.2-0.6,0.4-0.9,0.4s-0.7-0.1-0.9-0.4L8,11.6L4,15.5c-0.2,0.2-0.6,0.4-0.9,0.4
|
||||
s-0.7-0.1-0.9-0.4l-1.8-1.8C0.1,13.5,0,13.1,0,12.8s0.1-0.7,0.4-0.9L4.3,8L0.4,4C0.1,3.8,0,3.4,0,3.1s0.1-0.7,0.4-0.9l1.8-1.8
|
||||
C2.4,0.1,2.8,0,3.1,0S3.8,0.1,4,0.4L8,4.3l3.9-3.9C12.1,0.1,12.5,0,12.8,0s0.7,0.1,0.9,0.4l1.8,1.8c0.2,0.2,0.4,0.6,0.4,0.9
|
||||
S15.8,3.8,15.5,4L11.6,8l3.9,3.9c0.2,0.2,0.4,0.6,0.4,0.9S15.8,13.5,15.5,13.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 944 B |
5
interface/resources/resources.qrc
Normal file
5
interface/resources/resources.qrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>images/close.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
334
interface/resources/visage/tracker.cfg
Normal file
334
interface/resources/visage/tracker.cfg
Normal file
|
@ -0,0 +1,334 @@
|
|||
display_width 800
|
||||
|
||||
max_init_image_width 800
|
||||
max_work_image_width 384
|
||||
fast_image_resize 1
|
||||
|
||||
camera_input 0
|
||||
camera_device 0
|
||||
camera_width 800
|
||||
camera_height 600
|
||||
camera_frame_rate 30
|
||||
camera_mirror 1
|
||||
camera_settings_dialog 0
|
||||
camera_auto_settings 0
|
||||
|
||||
video_file_sync 1
|
||||
|
||||
automatic_initialisation 1
|
||||
init_yaw_threshold 0.005
|
||||
init_roll_threshold 10
|
||||
init_velocity_threshold 0.015
|
||||
init_timeout 1000
|
||||
init_timeout_enable 6
|
||||
init_display_status 1
|
||||
recovery_timeout 800
|
||||
|
||||
display_video 1
|
||||
display_model_texture 0
|
||||
display_tri_mask 0
|
||||
display_model_wireframe 0
|
||||
display_results 1
|
||||
display_track_points 0
|
||||
|
||||
detect_strip_area_threshold 1000
|
||||
detect_strip_angle_threshold 0.15
|
||||
detect_strip_ratio_threshold 0.2
|
||||
detect_strip_perfect_ratio 6.848
|
||||
detect_strip_roi_y_offset 0
|
||||
detect_strip_roi_width 2
|
||||
detect_strip_roi_height 4
|
||||
|
||||
smoothing_factors
|
||||
150 15 -2 100 -1 50 50 0
|
||||
#translation rotation action_units eyebrows mouth gaze eye_closure other
|
||||
|
||||
process_eyes 1
|
||||
leye_closing_au 12
|
||||
reye_closing_au 12
|
||||
eye_h_rotation_au 15
|
||||
eye_v_rotation_au 16
|
||||
eye_points_coords
|
||||
162 1.0 0.0 0.0
|
||||
157 0.0 0.0 1.0
|
||||
|
||||
bdts_points_use
|
||||
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
|
||||
#3.5 3.6 3.7 3.8 3.11 3.12 8.1 8.2 8.3 8.4 9.1 9.2 9.3 4.1 4.2 4.3 4.4 4.5 4.6 2.1
|
||||
|
||||
bdts_points_angle
|
||||
0 0 20 -20 20 -20 0 0 20 -20 20 -20 0 25 -25 20 -20 20 -20 0 0
|
||||
|
||||
model_filename candide3-exp.wfm
|
||||
fdp_filename candide3.fdp
|
||||
bdts_data_path bdtsdata
|
||||
|
||||
au_use
|
||||
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
|
||||
#AU1 AU2 AU3 AU4 AU5 AU6 AU7 AU8 AU9 AU10 AU11 AU12 AU13 AU14 AU15 AU16 AU17 AU18 AU19 AU20 AU21 AU22 AU23
|
||||
|
||||
au_names
|
||||
au_nose_wrinkler
|
||||
au_jaw_z_push
|
||||
au_jaw_x_push
|
||||
au_jaw_drop
|
||||
au_lower_lip_drop
|
||||
au_upper_lip_raiser
|
||||
au_lip_stretcher_left
|
||||
au_lip_corner_depressor
|
||||
au_lip_presser
|
||||
au_left_outer_brow_raiser
|
||||
au_left_inner_brow_raiser
|
||||
au_left_brow_lowerer
|
||||
au_leye_closed
|
||||
au_lid_tightener
|
||||
au_upper_lid_raiser
|
||||
au_rotate_eyes_left
|
||||
au_rotate_eyes_down
|
||||
au_lower_lip_x_push
|
||||
au_lip_stretcher_right
|
||||
au_right_outer_brow_raiser
|
||||
au_right_inner_brow_raiser
|
||||
au_right_brow_lowerer
|
||||
au_reye_closed
|
||||
|
||||
|
||||
ekf_sensitivity
|
||||
100 100 100 100 100 100 100 100 100 100 100 200 200 100 100 400 400 100 100 100 100 300 300 100 100 400 400 100 100
|
||||
#x y z rx ry rz AU1 AU2 AU3 AU4 AU5 AU6 AU7 AU8 AU9 AU10 AU11 AU12 AU13 AU14 AU15 AU16 AU17 AU18 AU19 AU20 AU21 AU22 AU23
|
||||
|
||||
au_gravity
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
#AU1 AU2 AU3 AU4 AU5 AU6 AU7 AU8 AU9 AU10 AU11 AU12 AU13 AU14 AU15 AU16 AU17 AU18 AU19 AU20 AU21 AU22 AU23
|
||||
|
||||
gravity_threshold 0.0
|
||||
|
||||
camera_focus 3
|
||||
|
||||
tex_size 512
|
||||
|
||||
ROI_num 14
|
||||
|
||||
#ROI 0 - nose region (setting default values)
|
||||
feature_points_num[0] 7
|
||||
feature_points_tri_use_num[0] 21
|
||||
feature_points_tri_use_list[0]
|
||||
48 154 54 55 152 45 46 47 103 109
|
||||
108 107 106 101 104 110 111 105 99 102
|
||||
100
|
||||
bound_rect_modifiers[0] -10 -10 -20 10
|
||||
feature_points_min_distance[0] 0.78125
|
||||
feature_point_block_size[0] 0.46875
|
||||
search_range[0] 4.0625 4.0625
|
||||
refine_range[0] 0.3125 0.3125
|
||||
patch_size[0] 4.6875
|
||||
match_method[0] 5
|
||||
bad_match_threshold[0] 0.35
|
||||
sensitivity_falloff[0] 10
|
||||
init_angle[0] 0
|
||||
feature_points_coords[0]
|
||||
97 0.18 0.54 0.28
|
||||
90 0.18 0.28 0.54
|
||||
51 0.76 0.09 0.15
|
||||
97 0.36 0.10 0.54
|
||||
90 0.36 0.54 0.10
|
||||
69 0.55 0.10 0.35
|
||||
67 0.55 0.35 0.10
|
||||
|
||||
#ROI 1 - left eyebrow region
|
||||
feature_points_num[1] 4
|
||||
feature_points_tri_use_num[1] 2
|
||||
feature_points_tri_use_list[1]
|
||||
25 26
|
||||
bound_rect_modifiers[1] 2 2 40 2
|
||||
feature_points_coords[1]
|
||||
25 0.0 0.0 1.0
|
||||
26 0.15 0.1 0.75
|
||||
25 1.0 0.0 0.0
|
||||
26 0.2 0.4 0.4
|
||||
|
||||
#ROI 2 - right eyebrow region
|
||||
feature_points_num[2] 4
|
||||
feature_points_tri_use_num[2] 2
|
||||
feature_points_tri_use_list[2]
|
||||
33 34
|
||||
bound_rect_modifiers[2] 2 2 40 2
|
||||
feature_points_coords[2]
|
||||
33 0.15 0.75 0.1
|
||||
34 1.0 0.0 0.0
|
||||
33 0.0 0.0 1.0
|
||||
33 0.2 0.4 0.4
|
||||
|
||||
#ROI 3 - left outer eye corner region
|
||||
feature_points_num[3] 3
|
||||
feature_points_tri_use_num[3] 4
|
||||
feature_points_tri_use_list[3]
|
||||
112 23 39 115
|
||||
bound_rect_modifiers[3] -5 -5 -25 -25
|
||||
feature_points_coords[3]
|
||||
23 0 0.2 0.8
|
||||
119 0.8351877 0.08414026 0.08067206
|
||||
116 0.3218788 0.4626164 0.2155048
|
||||
|
||||
#ROI 4 - right outer eye corner region
|
||||
feature_points_num[4] 3
|
||||
feature_points_tri_use_num[4] 4
|
||||
feature_points_tri_use_list[4]
|
||||
142 36 42 145
|
||||
bound_rect_modifiers[4] -5 -5 -25 -25
|
||||
feature_points_coords[4]
|
||||
36 0 0.8 0.2
|
||||
151 0.8566859 0.0405132 0.1028009
|
||||
146 0.2871178 0.3467231 0.366159
|
||||
|
||||
#ROI 5 - left inner eye corner region
|
||||
feature_points_num[5] 3
|
||||
feature_points_tri_use_num[5] 5
|
||||
feature_points_tri_use_list[5]
|
||||
122 28 99 100 125
|
||||
bound_rect_modifiers[5] -5 -5 -25 -40
|
||||
feature_points_coords[5]
|
||||
99 0.2 0.1 0.7
|
||||
122 0.2664618 0.3707059 0.3628323
|
||||
125 0.387767 0.4655813 0.1466517
|
||||
|
||||
#ROI 6 - right inner eye corner region
|
||||
feature_points_num[6] 3
|
||||
feature_points_tri_use_num[6] 5
|
||||
feature_points_tri_use_list[6]
|
||||
132 31 102 104 135
|
||||
bound_rect_modifiers[6] -5 -5 -25 -40
|
||||
feature_points_coords[6]
|
||||
102 0.2 0.7 0.1
|
||||
132 0.3673472 0.2426805 0.3899724
|
||||
135 0.2833096 0.1345753 0.5821151
|
||||
|
||||
#ROI 7 - lower lip region
|
||||
feature_points_num[7] 6
|
||||
feature_points_tri_use_num[7] 6
|
||||
feature_points_tri_use_list[7]
|
||||
79 80 82 84 52 53
|
||||
bound_rect_modifiers[7] 0 0 0 -80
|
||||
refine_range[7] 0.5 1
|
||||
patch_size[7] 7
|
||||
feature_points_coords[7]
|
||||
80 0.0 0.0 1.0
|
||||
80 1.0 0.0 0.0
|
||||
80 0.0 1.0 0.0
|
||||
79 0.0 0.0 1.0
|
||||
82 0.1 0.3 0.6
|
||||
84 0.1 0.6 0.3
|
||||
|
||||
#ROI 8 - upper lip region
|
||||
feature_points_num[8] 6
|
||||
feature_points_tri_use_num[8] 10
|
||||
feature_points_tri_use_list[8]
|
||||
69 49 155 51 50 153 44 67 57 60
|
||||
bound_rect_modifiers[8] 0 0 -70 0
|
||||
refine_range[8] 0.5 1
|
||||
patch_size[8] 7
|
||||
feature_points_coords[8]
|
||||
67 0.1 0.45 0.45
|
||||
69 0.1 0.45 0.45
|
||||
57 0.0 0.0 1.0
|
||||
60 0.0 1.0 0.0
|
||||
51 0.0 1.0 0.0
|
||||
51 0.3 0.7 0.0
|
||||
|
||||
#ROI 9 - left lip corner region
|
||||
feature_points_num[9] 4
|
||||
feature_points_tri_use_num[9] 4
|
||||
feature_points_tri_use_list[9]
|
||||
87 89 81 68
|
||||
bound_rect_modifiers[9] 0 0 -35 -35
|
||||
refine_range[9] 1 1
|
||||
patch_size[9] 7
|
||||
feature_points_coords[9]
|
||||
87 0.0 0.0 1.0
|
||||
87 0.2 0.0 0.8
|
||||
66 0.33 0.33 0.34
|
||||
72 0.33 0.33 0.34
|
||||
|
||||
#ROI 10 - right lip corner region
|
||||
feature_points_num[10] 4
|
||||
feature_points_tri_use_num[10] 4
|
||||
feature_points_tri_use_list[10]
|
||||
94 96 83 70
|
||||
bound_rect_modifiers[10] 0 0 -35 -35
|
||||
refine_range[10] 1 1
|
||||
patch_size[10] 7
|
||||
feature_points_coords[10]
|
||||
94 0.0 1.0 0.0
|
||||
94 0.2 0.8 0.0
|
||||
64 0.33 0.33 0.34
|
||||
78 0.33 0.33 0.34
|
||||
|
||||
#ROI 11 - jaw region
|
||||
feature_points_num[11] 4
|
||||
feature_points_tri_use_num[11] 2
|
||||
feature_points_tri_use_list[11]
|
||||
52 53
|
||||
bound_rect_modifiers[11] 0 0 -30 0
|
||||
refine_range[11] 0.5 1
|
||||
patch_size[11] 7
|
||||
bad_match_threshold[11] 0.6
|
||||
feature_points_coords[11]
|
||||
52 0.4 0.3 0.3
|
||||
53 0.4 0.3 0.3
|
||||
87 0.0 0.5 0.5
|
||||
94 0.0 0.5 0.5
|
||||
|
||||
feature_points_num[12] 6
|
||||
feature_points_tri_use_num[12] 3
|
||||
feature_points_tri_use_list[12]
|
||||
188 189 190 191
|
||||
bound_rect_modifiers[12] -30 0 0 -30
|
||||
init_angle[12] -20
|
||||
|
||||
feature_points_num[13] 6
|
||||
feature_points_tri_use_num[13] 3
|
||||
feature_points_tri_use_list[13]
|
||||
192 193 194 195
|
||||
bound_rect_modifiers[13] 0 -30 0 -30
|
||||
init_angle[13] 20
|
||||
|
||||
recovery_frames 4
|
||||
global_bad_match_threshold 0.5
|
||||
visibility_check 1
|
||||
|
||||
rotation_limit
|
||||
-1.570796 1.570796
|
||||
1.570796 4.712389
|
||||
-3.2 3.2
|
||||
|
||||
translation_limit
|
||||
-4 4
|
||||
-3 3
|
||||
0 11
|
||||
|
||||
action_unit_limit
|
||||
-0.5 0.5
|
||||
-0.5 0.5
|
||||
-1.0 1.0
|
||||
-0.05 1.2
|
||||
-0.05 1.5
|
||||
-0.05 1.5
|
||||
-1.0 1.0
|
||||
-1.5 1.5
|
||||
-1.5 1.5
|
||||
-1.5 2
|
||||
-1.5 2
|
||||
-1 1.5
|
||||
-2.8 2.8
|
||||
-1.5 1.5
|
||||
-1.5 1.5
|
||||
-100 100
|
||||
-100 100
|
||||
-1.5 1.5
|
||||
-1.5 1.5
|
||||
-1.5 1.5
|
||||
-1.5 1.5
|
||||
-1.5 1.5
|
||||
-2.8 2.8
|
||||
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
#include <PerfStat.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <UUID.h>
|
||||
#include <VoxelSceneStats.h>
|
||||
#include <OctreeSceneStats.h>
|
||||
#include <LocalVoxelsList.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
@ -140,9 +140,13 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
_fps(120.0f),
|
||||
_justStarted(true),
|
||||
_voxelImporter(NULL),
|
||||
_importSucceded(false),
|
||||
_sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard),
|
||||
_wantToKillLocalVoxels(false),
|
||||
_viewFrustum(),
|
||||
_lastQueriedViewFrustum(),
|
||||
_lastQueriedTime(usecTimestampNow()),
|
||||
_audioScope(256, 200, true),
|
||||
_myAvatar(),
|
||||
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
||||
_mouseX(0),
|
||||
_mouseY(0),
|
||||
|
@ -153,7 +157,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
_touchAvgY(0.0f),
|
||||
_isTouchPressed(false),
|
||||
_mousePressed(false),
|
||||
_chatEntryOn(false),
|
||||
_audio(&_audioScope, STARTUP_JITTER_SAMPLES),
|
||||
_enableProcessVoxelsThread(true),
|
||||
_voxelProcessor(),
|
||||
|
@ -507,7 +510,7 @@ void Application::paintGL() {
|
|||
float headHeight = _myAvatar->getHead()->calculateAverageEyePosition().y - _myAvatar->getPosition().y;
|
||||
_myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale());
|
||||
_myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0));
|
||||
_myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
||||
_myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f)));
|
||||
}
|
||||
|
||||
// Update camera position
|
||||
|
@ -698,21 +701,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
|
||||
if (activeWindow() == _window) {
|
||||
if (_chatEntryOn) {
|
||||
if (_chatEntry.keyPressEvent(event)) {
|
||||
_myAvatar->setKeyState(event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete ?
|
||||
DELETE_KEY_DOWN : INSERT_KEY_DOWN);
|
||||
_myAvatar->setChatMessage(string(_chatEntry.getContents().size(), SOLID_BLOCK_CHAR));
|
||||
|
||||
} else {
|
||||
_myAvatar->setChatMessage(_chatEntry.getContents());
|
||||
_chatEntry.clear();
|
||||
_chatEntryOn = false;
|
||||
setMenuShortcutsEnabled(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier);
|
||||
bool isMeta = event->modifiers().testFlag(Qt::ControlModifier);
|
||||
switch (event->key()) {
|
||||
|
@ -744,7 +732,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
if (!_myAvatar->getDriveKeys(UP)) {
|
||||
_myAvatar->jump();
|
||||
}
|
||||
_myAvatar->setDriveKeys(UP, 1);
|
||||
_myAvatar->setDriveKeys(UP, 1.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_Asterisk:
|
||||
|
@ -752,11 +740,11 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_C:
|
||||
_myAvatar->setDriveKeys(DOWN, 1);
|
||||
_myAvatar->setDriveKeys(DOWN, 1.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_W:
|
||||
_myAvatar->setDriveKeys(FWD, 1);
|
||||
_myAvatar->setDriveKeys(FWD, 1.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_S:
|
||||
|
@ -765,7 +753,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
} else if (!isShifted && isMeta) {
|
||||
takeSnapshot();
|
||||
} else {
|
||||
_myAvatar->setDriveKeys(BACK, 1);
|
||||
_myAvatar->setDriveKeys(BACK, 1.f);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -783,36 +771,33 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
if (isShifted) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::Atmosphere);
|
||||
} else {
|
||||
_myAvatar->setDriveKeys(ROT_LEFT, 1);
|
||||
_myAvatar->setDriveKeys(ROT_LEFT, 1.f);
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_D:
|
||||
_myAvatar->setDriveKeys(ROT_RIGHT, 1);
|
||||
_myAvatar->setDriveKeys(ROT_RIGHT, 1.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
_chatEntryOn = true;
|
||||
_myAvatar->setKeyState(NO_KEY_DOWN);
|
||||
_myAvatar->setChatMessage(string());
|
||||
setMenuShortcutsEnabled(false);
|
||||
Menu::getInstance()->triggerOption(MenuOption::Chat);
|
||||
break;
|
||||
|
||||
case Qt::Key_Up:
|
||||
_myAvatar->setDriveKeys(isShifted ? UP : FWD, 1);
|
||||
_myAvatar->setDriveKeys(isShifted ? UP : FWD, 1.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
_myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1);
|
||||
_myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_Left:
|
||||
_myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1);
|
||||
_myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_Right:
|
||||
_myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1);
|
||||
_myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_I:
|
||||
|
@ -939,54 +924,49 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
|
|||
|
||||
|
||||
if (activeWindow() == _window) {
|
||||
if (_chatEntryOn) {
|
||||
_myAvatar->setKeyState(NO_KEY_DOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_E:
|
||||
_myAvatar->setDriveKeys(UP, 0);
|
||||
_myAvatar->setDriveKeys(UP, 0.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_C:
|
||||
_myAvatar->setDriveKeys(DOWN, 0);
|
||||
_myAvatar->setDriveKeys(DOWN, 0.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_W:
|
||||
_myAvatar->setDriveKeys(FWD, 0);
|
||||
_myAvatar->setDriveKeys(FWD, 0.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_S:
|
||||
_myAvatar->setDriveKeys(BACK, 0);
|
||||
_myAvatar->setDriveKeys(BACK, 0.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_A:
|
||||
_myAvatar->setDriveKeys(ROT_LEFT, 0);
|
||||
_myAvatar->setDriveKeys(ROT_LEFT, 0.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_D:
|
||||
_myAvatar->setDriveKeys(ROT_RIGHT, 0);
|
||||
_myAvatar->setDriveKeys(ROT_RIGHT, 0.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_Up:
|
||||
_myAvatar->setDriveKeys(FWD, 0);
|
||||
_myAvatar->setDriveKeys(UP, 0);
|
||||
_myAvatar->setDriveKeys(FWD, 0.f);
|
||||
_myAvatar->setDriveKeys(UP, 0.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
_myAvatar->setDriveKeys(BACK, 0);
|
||||
_myAvatar->setDriveKeys(DOWN, 0);
|
||||
_myAvatar->setDriveKeys(BACK, 0.f);
|
||||
_myAvatar->setDriveKeys(DOWN, 0.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_Left:
|
||||
_myAvatar->setDriveKeys(LEFT, 0);
|
||||
_myAvatar->setDriveKeys(ROT_LEFT, 0);
|
||||
_myAvatar->setDriveKeys(LEFT, 0.f);
|
||||
_myAvatar->setDriveKeys(ROT_LEFT, 0.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_Right:
|
||||
_myAvatar->setDriveKeys(RIGHT, 0);
|
||||
_myAvatar->setDriveKeys(ROT_RIGHT, 0);
|
||||
_myAvatar->setDriveKeys(RIGHT, 0.f);
|
||||
_myAvatar->setDriveKeys(ROT_RIGHT, 0.f);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1138,7 +1118,6 @@ void Application::touchEndEvent(QTouchEvent* event) {
|
|||
|
||||
}
|
||||
|
||||
const bool USE_MOUSEWHEEL = false;
|
||||
void Application::wheelEvent(QWheelEvent* event) {
|
||||
|
||||
_controllerScriptingInterface.emitWheelEvent(event); // send events to any registered scripts
|
||||
|
@ -1242,8 +1221,10 @@ void Application::idle() {
|
|||
_idleLoopStdev.reset();
|
||||
}
|
||||
|
||||
_buckyBalls.simulate(timeSinceLastUpdate / 1000.f, Application::getInstance()->getAvatar()->getHandData());
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) {
|
||||
_buckyBalls.simulate(timeSinceLastUpdate / 1000.f, Application::getInstance()->getAvatar()->getHandData());
|
||||
}
|
||||
|
||||
// After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
|
||||
idleTimer->start(2);
|
||||
}
|
||||
|
@ -1327,7 +1308,6 @@ glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail& mouseVox
|
|||
(mouseVoxel.z + mouseVoxel.s / 2.f) * TREE_SCALE);
|
||||
}
|
||||
|
||||
const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500;
|
||||
struct SendVoxelsOperationArgs {
|
||||
const unsigned char* newBaseOctCode;
|
||||
};
|
||||
|
@ -1389,6 +1369,8 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) {
|
|||
}
|
||||
|
||||
void Application::importVoxels() {
|
||||
_importSucceded = false;
|
||||
|
||||
if (!_voxelImporter) {
|
||||
_voxelImporter = new VoxelImporter(_window);
|
||||
_voxelImporter->loadSettings(_settings);
|
||||
|
@ -1396,6 +1378,7 @@ void Application::importVoxels() {
|
|||
|
||||
if (!_voxelImporter->exec()) {
|
||||
qDebug() << "[DEBUG] Import succeeded." << endl;
|
||||
_importSucceded = true;
|
||||
} else {
|
||||
qDebug() << "[DEBUG] Import failed." << endl;
|
||||
if (_sharedVoxelSystem.getTree() == _voxelImporter->getVoxelTree()) {
|
||||
|
@ -1406,6 +1389,8 @@ void Application::importVoxels() {
|
|||
|
||||
// restore the main window's active state
|
||||
_window->activateWindow();
|
||||
|
||||
emit importDone();
|
||||
}
|
||||
|
||||
void Application::cutVoxels(const VoxelDetail& sourceVoxel) {
|
||||
|
@ -1488,7 +1473,7 @@ void Application::init() {
|
|||
3.0f * TREE_SCALE / 2.0f));
|
||||
_sharedVoxelSystemViewFrustum.setNearClip(TREE_SCALE / 2.0f);
|
||||
_sharedVoxelSystemViewFrustum.setFarClip(3.0f * TREE_SCALE / 2.0f);
|
||||
_sharedVoxelSystemViewFrustum.setFieldOfView(90);
|
||||
_sharedVoxelSystemViewFrustum.setFieldOfView(90.f);
|
||||
_sharedVoxelSystemViewFrustum.setOrientation(glm::quat());
|
||||
_sharedVoxelSystemViewFrustum.calculate();
|
||||
_sharedVoxelSystem.setViewFrustum(&_sharedVoxelSystemViewFrustum);
|
||||
|
@ -1497,10 +1482,9 @@ void Application::init() {
|
|||
|
||||
// Cleanup of the original shared tree
|
||||
_sharedVoxelSystem.init();
|
||||
VoxelTree* tmpTree = _sharedVoxelSystem.getTree();
|
||||
_sharedVoxelSystem.changeTree(&_clipboard);
|
||||
delete tmpTree;
|
||||
|
||||
|
||||
_voxelImporter = new VoxelImporter(_window);
|
||||
|
||||
_environment.init();
|
||||
|
||||
_glowEffect.init();
|
||||
|
@ -1607,8 +1591,6 @@ void Application::shrinkMirrorView() {
|
|||
}
|
||||
}
|
||||
|
||||
const float MAX_AVATAR_EDIT_VELOCITY = 1.0f;
|
||||
const float MAX_VOXEL_EDIT_DISTANCE = 50.0f;
|
||||
const float HEAD_SPHERE_RADIUS = 0.07f;
|
||||
|
||||
bool Application::isLookingAtMyAvatar(Avatar* avatar) {
|
||||
|
@ -1825,9 +1807,9 @@ void Application::updateDialogs(float deltaTime) {
|
|||
bandwidthDialog->update();
|
||||
}
|
||||
|
||||
VoxelStatsDialog* voxelStatsDialog = Menu::getInstance()->getVoxelStatsDialog();
|
||||
if (voxelStatsDialog) {
|
||||
voxelStatsDialog->update();
|
||||
OctreeStatsDialog* octreeStatsDialog = Menu::getInstance()->getOctreeStatsDialog();
|
||||
if (octreeStatsDialog) {
|
||||
octreeStatsDialog->update();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1921,8 +1903,19 @@ void Application::updateMyAvatar(float deltaTime) {
|
|||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
|
||||
// Update my voxel servers with my current voxel query...
|
||||
queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions);
|
||||
queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions);
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 sinceLastQuery = now - _lastQueriedTime;
|
||||
const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND;
|
||||
bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY;
|
||||
bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum);
|
||||
|
||||
// if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it
|
||||
if (queryIsDue || viewIsDifferentEnough) {
|
||||
_lastQueriedTime = now;
|
||||
queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions);
|
||||
queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions);
|
||||
_lastQueriedViewFrustum = _viewFrustum;
|
||||
}
|
||||
}
|
||||
|
||||
void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) {
|
||||
|
@ -2120,7 +2113,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {
|
||||
// We will use these below, from either the camera or head vectors calculated above
|
||||
glm::vec3 position(camera.getPosition());
|
||||
float fov = camera.getFieldOfView();
|
||||
float fov = camera.getFieldOfView(); // degrees
|
||||
float nearClip = camera.getNearClip();
|
||||
float farClip = camera.getFarClip();
|
||||
float aspectRatio = camera.getAspectRatio();
|
||||
|
@ -2133,7 +2126,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {
|
|||
|
||||
// Also make sure it's got the correct lens details from the camera
|
||||
viewFrustum.setAspectRatio(aspectRatio);
|
||||
viewFrustum.setFieldOfView(fov);
|
||||
viewFrustum.setFieldOfView(fov); // degrees
|
||||
viewFrustum.setNearClip(nearClip);
|
||||
viewFrustum.setFarClip(farClip);
|
||||
viewFrustum.setEyeOffsetPosition(camera.getEyeOffsetPosition());
|
||||
|
@ -2195,7 +2188,7 @@ void Application::updateShadowMap() {
|
|||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
// store view matrix without translation, which we'll use for precision-sensitive objects
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix);
|
||||
|
@ -2274,7 +2267,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
glm::vec3 eyeOffsetPos = whichCamera.getEyeOffsetPosition();
|
||||
glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation();
|
||||
glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient);
|
||||
glRotatef(-glm::angle(eyeOffsetOrient), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z);
|
||||
glRotatef(-glm::degrees(glm::angle(eyeOffsetOrient)), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z);
|
||||
glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z);
|
||||
|
||||
// transform view according to whichCamera
|
||||
|
@ -2283,7 +2276,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
|
||||
glm::quat rotation = whichCamera.getRotation();
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(-glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
// store view matrix without translation, which we'll use for precision-sensitive objects
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix);
|
||||
|
@ -2487,11 +2480,6 @@ void Application::displayOverlay() {
|
|||
}
|
||||
}
|
||||
|
||||
// Show chat entry field
|
||||
if (_chatEntryOn) {
|
||||
_chatEntry.render(_glWidget->width(), _glWidget->height());
|
||||
}
|
||||
|
||||
// Show on-screen msec timer
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
|
||||
char frameTimer[10];
|
||||
|
@ -2501,7 +2489,7 @@ void Application::displayOverlay() {
|
|||
(Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
|
||||
? 80 : 20;
|
||||
drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 1.0f, 0, frameTimer, WHITE_TEXT);
|
||||
drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 1.0f, 0.f, frameTimer, WHITE_TEXT);
|
||||
}
|
||||
|
||||
_overlays.render2D();
|
||||
|
@ -2556,11 +2544,11 @@ void Application::displayStats() {
|
|||
sprintf(framesPerSecond, "Framerate: %3.0f FPS", _fps);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, serverNodes, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, serverNodes, WHITE_TEXT);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarNodes, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarNodes, WHITE_TEXT);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, framesPerSecond, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, framesPerSecond, WHITE_TEXT);
|
||||
|
||||
if (_statsExpanded) {
|
||||
char packetsPerSecond[30];
|
||||
|
@ -2569,9 +2557,9 @@ void Application::displayStats() {
|
|||
sprintf(averageMegabitsPerSecond, "Mbps: %3.2f", (float)_bytesPerSecond * 8.f / 1000000.f);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, packetsPerSecond, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, packetsPerSecond, WHITE_TEXT);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, averageMegabitsPerSecond, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, averageMegabitsPerSecond, WHITE_TEXT);
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
|
@ -2614,7 +2602,7 @@ void Application::displayStats() {
|
|||
"Buffer msecs %.1f",
|
||||
(float) (_audio.getNetworkBufferLengthSamplesPerChannel() + (float) _audio.getJitterBufferSamples()) /
|
||||
(float)_audio.getNetworkSampleRate() * 1000.f);
|
||||
drawText(30, _glWidget->height() - 22, 0.10f, 0, 2, audioJitter, WHITE_TEXT);
|
||||
drawText(30, _glWidget->height() - 22, 0.10f, 0.f, 2.f, audioJitter, WHITE_TEXT);
|
||||
|
||||
|
||||
char audioPing[30];
|
||||
|
@ -2627,18 +2615,18 @@ void Application::displayStats() {
|
|||
sprintf(voxelAvgPing, "Voxel avg ping: %d", pingVoxel);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, audioPing, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, audioPing, WHITE_TEXT);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarPing, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPing, WHITE_TEXT);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, voxelAvgPing, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelAvgPing, WHITE_TEXT);
|
||||
|
||||
if (_statsExpanded) {
|
||||
char voxelMaxPing[30];
|
||||
sprintf(voxelMaxPing, "Voxel max ping: %d", pingVoxelMax);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, voxelMaxPing, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelMaxPing, WHITE_TEXT);
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
|
@ -2666,11 +2654,11 @@ void Application::displayStats() {
|
|||
char avatarMixerStats[200];
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarPosition, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPosition, WHITE_TEXT);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarVelocity, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarVelocity, WHITE_TEXT);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarBodyYaw, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarBodyYaw, WHITE_TEXT);
|
||||
|
||||
if (_statsExpanded) {
|
||||
SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AvatarMixer);
|
||||
|
@ -2683,7 +2671,7 @@ void Application::displayStats() {
|
|||
}
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarMixerStats, WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarMixerStats, WHITE_TEXT);
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
|
@ -2698,7 +2686,7 @@ void Application::displayStats() {
|
|||
voxelStats.str("");
|
||||
voxelStats << "Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.f << "MB";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
|
||||
voxelStats.str("");
|
||||
voxelStats <<
|
||||
|
@ -2708,14 +2696,14 @@ void Application::displayStats() {
|
|||
voxelStats << " / GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB";
|
||||
}
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
|
||||
// Voxel Rendering
|
||||
voxelStats.str("");
|
||||
voxelStats.precision(4);
|
||||
voxelStats << "Voxel Rendering Slots Max: " << _voxels.getMaxVoxels() / 1000.f << "K";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
}
|
||||
|
||||
voxelStats.str("");
|
||||
|
@ -2723,7 +2711,7 @@ void Application::displayStats() {
|
|||
voxelStats << "Drawn: " << _voxels.getVoxelsWritten() / 1000.f << "K " <<
|
||||
"Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K ";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
|
||||
// iterate all the current voxel stats, and list their sending modes, and total voxel counts
|
||||
std::stringstream sendingMode("");
|
||||
|
@ -2733,9 +2721,9 @@ void Application::displayStats() {
|
|||
unsigned long totalNodes = 0;
|
||||
unsigned long totalInternal = 0;
|
||||
unsigned long totalLeaves = 0;
|
||||
for(NodeToVoxelSceneStatsIterator i = _octreeServerSceneStats.begin(); i != _octreeServerSceneStats.end(); i++) {
|
||||
for(NodeToOctreeSceneStatsIterator i = _octreeServerSceneStats.begin(); i != _octreeServerSceneStats.end(); i++) {
|
||||
//const QUuid& uuid = i->first;
|
||||
VoxelSceneStats& stats = i->second;
|
||||
OctreeSceneStats& stats = i->second;
|
||||
serverCount++;
|
||||
if (_statsExpanded) {
|
||||
if (serverCount > 1) {
|
||||
|
@ -2767,7 +2755,7 @@ void Application::displayStats() {
|
|||
sendingMode << " <SCENE STABLE>";
|
||||
}
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)sendingMode.str().c_str(), WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)sendingMode.str().c_str(), WHITE_TEXT);
|
||||
}
|
||||
|
||||
// Incoming packets
|
||||
|
@ -2776,10 +2764,10 @@ void Application::displayStats() {
|
|||
voxelStats.str("");
|
||||
QString packetsString = locale.toString((int)voxelPacketsToProcess);
|
||||
QString maxString = locale.toString((int)_recentMaxPackets);
|
||||
voxelStats << "Voxel Packets to Process: " << packetsString.toLocal8Bit().constData()
|
||||
<< " [Recent Max: " << maxString.toLocal8Bit().constData() << "]";
|
||||
voxelStats << "Voxel Packets to Process: " << qPrintable(packetsString)
|
||||
<< " [Recent Max: " << qPrintable(maxString) << "]";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
}
|
||||
|
||||
if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) {
|
||||
|
@ -2800,9 +2788,9 @@ void Application::displayStats() {
|
|||
|
||||
// Server Voxels
|
||||
voxelStats.str("");
|
||||
voxelStats << "Server voxels: " << serversTotalString.toLocal8Bit().constData();
|
||||
voxelStats << "Server voxels: " << qPrintable(serversTotalString);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
|
||||
if (_statsExpanded) {
|
||||
QString serversInternalString = locale.toString((uint)totalInternal);
|
||||
|
@ -2810,10 +2798,10 @@ void Application::displayStats() {
|
|||
|
||||
voxelStats.str("");
|
||||
voxelStats <<
|
||||
"Internal: " << serversInternalString.toLocal8Bit().constData() << " " <<
|
||||
"Leaves: " << serversLeavesString.toLocal8Bit().constData() << "";
|
||||
"Internal: " << qPrintable(serversInternalString) << " " <<
|
||||
"Leaves: " << qPrintable(serversLeavesString) << "";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
}
|
||||
|
||||
unsigned long localTotal = VoxelTreeElement::getNodeCount();
|
||||
|
@ -2821,9 +2809,9 @@ void Application::displayStats() {
|
|||
|
||||
// Local Voxels
|
||||
voxelStats.str("");
|
||||
voxelStats << "Local voxels: " << localTotalString.toLocal8Bit().constData();
|
||||
voxelStats << "Local voxels: " << qPrintable(localTotalString);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
|
||||
if (_statsExpanded) {
|
||||
unsigned long localInternal = VoxelTreeElement::getInternalNodeCount();
|
||||
|
@ -2833,11 +2821,20 @@ void Application::displayStats() {
|
|||
|
||||
voxelStats.str("");
|
||||
voxelStats <<
|
||||
"Internal: " << localInternalString.toLocal8Bit().constData() << " " <<
|
||||
"Leaves: " << localLeavesString.toLocal8Bit().constData() << "";
|
||||
"Internal: " << qPrintable(localInternalString) << " " <<
|
||||
"Leaves: " << qPrintable(localLeavesString) << "";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
}
|
||||
|
||||
// LOD Details
|
||||
if (_statsExpanded) {
|
||||
voxelStats.str("");
|
||||
QString displayLODDetails = Menu::getInstance()->getLODFeedbackText();
|
||||
voxelStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed());
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
// called on mouse click release
|
||||
|
@ -2927,17 +2924,17 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
|
|||
void Application::renderRearViewMirror(const QRect& region, bool billboard) {
|
||||
bool eyeRelativeCamera = false;
|
||||
if (billboard) {
|
||||
_mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW);
|
||||
_mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees
|
||||
_mirrorCamera.setDistance(BILLBOARD_DISTANCE * _myAvatar->getScale());
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getPosition());
|
||||
|
||||
} else if (_rearMirrorTools->getZoomLevel() == BODY) {
|
||||
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW);
|
||||
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees
|
||||
_mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getChestPosition());
|
||||
|
||||
} else { // HEAD zoom level
|
||||
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW);
|
||||
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees
|
||||
_mirrorCamera.setDistance(MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
|
||||
if (_myAvatar->getSkeletonModel().isActive() && _myAvatar->getHead()->getFaceModel().isActive()) {
|
||||
// as a hack until we have a better way of dealing with coordinate precision issues, reposition the
|
||||
|
@ -2951,7 +2948,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
|
|||
}
|
||||
_mirrorCamera.setAspectRatio((float)region.width() / region.height());
|
||||
|
||||
_mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
||||
_mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f)));
|
||||
_mirrorCamera.update(1.0f/_fps);
|
||||
|
||||
// set the bounds of rear mirror view
|
||||
|
@ -3288,11 +3285,11 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
}
|
||||
|
||||
// also clean up scene stats for that server
|
||||
_voxelSceneStatsLock.lockForWrite();
|
||||
_octreeSceneStatsLock.lockForWrite();
|
||||
if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) {
|
||||
_octreeServerSceneStats.erase(nodeUUID);
|
||||
}
|
||||
_voxelSceneStatsLock.unlock();
|
||||
_octreeSceneStatsLock.unlock();
|
||||
|
||||
} else if (node->getType() == NodeType::ParticleServer) {
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
|
@ -3319,11 +3316,11 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
}
|
||||
|
||||
// also clean up scene stats for that server
|
||||
_voxelSceneStatsLock.lockForWrite();
|
||||
_octreeSceneStatsLock.lockForWrite();
|
||||
if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) {
|
||||
_octreeServerSceneStats.erase(nodeUUID);
|
||||
}
|
||||
_voxelSceneStatsLock.unlock();
|
||||
_octreeSceneStatsLock.unlock();
|
||||
|
||||
} else if (node->getType() == NodeType::AvatarMixer) {
|
||||
// our avatar mixer has gone away - clear the hash of avatars
|
||||
|
@ -3338,12 +3335,12 @@ void Application::trackIncomingVoxelPacket(const QByteArray& packet, const Share
|
|||
QUuid nodeUUID = sendingNode->getUUID();
|
||||
|
||||
// now that we know the node ID, let's add these stats to the stats for that node...
|
||||
_voxelSceneStatsLock.lockForWrite();
|
||||
_octreeSceneStatsLock.lockForWrite();
|
||||
if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) {
|
||||
VoxelSceneStats& stats = _octreeServerSceneStats[nodeUUID];
|
||||
OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID];
|
||||
stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec());
|
||||
}
|
||||
_voxelSceneStatsLock.unlock();
|
||||
_octreeSceneStatsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3353,7 +3350,7 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin
|
|||
|
||||
// parse the incoming stats datas stick it in a temporary object for now, while we
|
||||
// determine which server it belongs to
|
||||
VoxelSceneStats temp;
|
||||
OctreeSceneStats temp;
|
||||
int statsMessageLength = temp.unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()), packet.size());
|
||||
|
||||
// quick fix for crash... why would voxelServer be NULL?
|
||||
|
@ -3361,14 +3358,14 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin
|
|||
QUuid nodeUUID = sendingNode->getUUID();
|
||||
|
||||
// now that we know the node ID, let's add these stats to the stats for that node...
|
||||
_voxelSceneStatsLock.lockForWrite();
|
||||
_octreeSceneStatsLock.lockForWrite();
|
||||
if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) {
|
||||
_octreeServerSceneStats[nodeUUID].unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()),
|
||||
packet.size());
|
||||
} else {
|
||||
_octreeServerSceneStats[nodeUUID] = temp;
|
||||
}
|
||||
_voxelSceneStatsLock.unlock();
|
||||
_octreeSceneStatsLock.unlock();
|
||||
|
||||
VoxelPositionSize rootDetails;
|
||||
voxelDetailsForCode(temp.getJurisdictionRoot(), rootDetails);
|
||||
|
@ -3397,8 +3394,8 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin
|
|||
}
|
||||
// store jurisdiction details for later use
|
||||
// This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it
|
||||
// but VoxelSceneStats thinks it's just returning a reference to it's contents. So we need to make a copy of the
|
||||
// details from the VoxelSceneStats to construct the JurisdictionMap
|
||||
// but OctreeSceneStats thinks it's just returning a reference to it's contents. So we need to make a copy of the
|
||||
// details from the OctreeSceneStats to construct the JurisdictionMap
|
||||
JurisdictionMap jurisdictionMap;
|
||||
jurisdictionMap.copyContents(temp.getJurisdictionRoot(), temp.getJurisdictionEndNodes());
|
||||
(*jurisdiction)[nodeUUID] = jurisdictionMap;
|
||||
|
|
|
@ -64,8 +64,7 @@
|
|||
#include "renderer/TextureCache.h"
|
||||
#include "renderer/VoxelShader.h"
|
||||
#include "ui/BandwidthDialog.h"
|
||||
#include "ui/ChatEntry.h"
|
||||
#include "ui/VoxelStatsDialog.h"
|
||||
#include "ui/OctreeStatsDialog.h"
|
||||
#include "ui/RearMirrorTools.h"
|
||||
#include "ui/LodToolsDialog.h"
|
||||
#include "ui/LogDialog.h"
|
||||
|
@ -95,8 +94,8 @@ static const float NODE_KILLED_BLUE = 0.0f;
|
|||
|
||||
static const QString SNAPSHOT_EXTENSION = ".jpg";
|
||||
|
||||
static const float BILLBOARD_FIELD_OF_VIEW = 30.0f;
|
||||
static const float BILLBOARD_DISTANCE = 5.0f;
|
||||
static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; // degrees
|
||||
static const float BILLBOARD_DISTANCE = 5.0f; // meters
|
||||
|
||||
class Application : public QApplication {
|
||||
Q_OBJECT
|
||||
|
@ -157,6 +156,7 @@ public:
|
|||
VoxelTree* getVoxelTree() { return _voxels.getTree(); }
|
||||
ParticleTreeRenderer* getParticles() { return &_particles; }
|
||||
MetavoxelSystem* getMetavoxels() { return &_metavoxels; }
|
||||
bool getImportSucceded() { return _importSucceded; }
|
||||
VoxelSystem* getSharedVoxelSystem() { return &_sharedVoxelSystem; }
|
||||
VoxelTree* getClipboard() { return &_clipboard; }
|
||||
Environment* getEnvironment() { return &_environment; }
|
||||
|
@ -170,9 +170,9 @@ public:
|
|||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||
QSettings* getSettings() { return _settings; }
|
||||
QMainWindow* getWindow() { return _window; }
|
||||
NodeToVoxelSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
|
||||
void lockVoxelSceneStats() { _voxelSceneStatsLock.lockForRead(); }
|
||||
void unlockVoxelSceneStats() { _voxelSceneStatsLock.unlock(); }
|
||||
NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
|
||||
void lockOctreeSceneStats() { _octreeSceneStatsLock.lockForRead(); }
|
||||
void unlockOctreeSceneStats() { _octreeSceneStatsLock.unlock(); }
|
||||
|
||||
QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; }
|
||||
GeometryCache* getGeometryCache() { return &_geometryCache; }
|
||||
|
@ -225,6 +225,9 @@ signals:
|
|||
/// Fired when we're rendering in-world interface elements; allows external parties to hook in.
|
||||
void renderingInWorldInterface();
|
||||
|
||||
/// Fired when the import window is closed
|
||||
void importDone();
|
||||
|
||||
public slots:
|
||||
void domainChanged(const QString& domainHostname);
|
||||
void updateWindowTitle();
|
||||
|
@ -351,13 +354,13 @@ private:
|
|||
glm::vec3 _gravity;
|
||||
|
||||
// Frame Rate Measurement
|
||||
|
||||
int _frameCount;
|
||||
float _fps;
|
||||
timeval _applicationStartupTime;
|
||||
timeval _timerStart, _timerEnd;
|
||||
timeval _lastTimeUpdated;
|
||||
bool _justStarted;
|
||||
|
||||
Stars _stars;
|
||||
|
||||
BuckyBalls _buckyBalls;
|
||||
|
@ -365,6 +368,7 @@ private:
|
|||
VoxelSystem _voxels;
|
||||
VoxelTree _clipboard; // if I copy/paste
|
||||
VoxelImporter* _voxelImporter;
|
||||
bool _importSucceded;
|
||||
VoxelSystem _sharedVoxelSystem;
|
||||
ViewFrustum _sharedVoxelSystemViewFrustum;
|
||||
|
||||
|
@ -377,6 +381,8 @@ private:
|
|||
MetavoxelSystem _metavoxels;
|
||||
|
||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels, particles)
|
||||
quint64 _lastQueriedTime;
|
||||
|
||||
Oscilloscope _audioScope;
|
||||
|
||||
|
@ -426,9 +432,6 @@ private:
|
|||
|
||||
bool _mousePressed; // true if mouse has been pressed (clear when finished)
|
||||
|
||||
ChatEntry _chatEntry; // chat entry field
|
||||
bool _chatEntryOn; // Whether to show the chat entry
|
||||
|
||||
GeometryCache _geometryCache;
|
||||
TextureCache _textureCache;
|
||||
|
||||
|
@ -459,8 +462,8 @@ private:
|
|||
|
||||
NodeToJurisdictionMap _voxelServerJurisdictions;
|
||||
NodeToJurisdictionMap _particleServerJurisdictions;
|
||||
NodeToVoxelSceneStats _octreeServerSceneStats;
|
||||
QReadWriteLock _voxelSceneStatsLock;
|
||||
NodeToOctreeSceneStats _octreeServerSceneStats;
|
||||
QReadWriteLock _octreeSceneStatsLock;
|
||||
|
||||
std::vector<VoxelFade> _voxelFades;
|
||||
ControllerScriptingInterface _controllerScriptingInterface;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <QtMultimedia/QAudioOutput>
|
||||
#include <QSvgRenderer>
|
||||
|
||||
#include <AngleUtil.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
|
@ -32,9 +31,6 @@
|
|||
#include "Menu.h"
|
||||
#include "Util.h"
|
||||
|
||||
static const float JITTER_BUFFER_LENGTH_MSECS = 12;
|
||||
static const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * NUM_AUDIO_CHANNELS * (SAMPLE_RATE / 1000.0);
|
||||
|
||||
static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0;
|
||||
|
||||
static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300;
|
||||
|
@ -656,7 +652,7 @@ void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) {
|
|||
const float MAX_DURATION = 2.f;
|
||||
const float MIN_AUDIBLE_VOLUME = 0.001f;
|
||||
const float NOISE_MAGNITUDE = 0.02f;
|
||||
float frequency = (_drumSoundFrequency / SAMPLE_RATE) * PI_TIMES_TWO;
|
||||
float frequency = (_drumSoundFrequency / SAMPLE_RATE) * TWO_PI;
|
||||
if (_drumSoundVolume > 0.f) {
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
t = (float) _drumSoundSample + (float) i;
|
||||
|
|
|
@ -81,7 +81,7 @@ void Camera::updateFollowMode(float deltaTime) {
|
|||
_distance = _newDistance;
|
||||
_tightness = _newTightness;
|
||||
} else {
|
||||
_modeShift = ONE_HALF - ONE_HALF * cosf(_linearModeShift * PIE );
|
||||
_modeShift = ONE_HALF - ONE_HALF * cosf(_linearModeShift * PI );
|
||||
_upShift = _previousUpShift * (1.0f - _modeShift) + _newUpShift * _modeShift;
|
||||
_distance = _previousDistance * (1.0f - _modeShift) + _newDistance * _modeShift;
|
||||
_tightness = _previousTightness * (1.0f - _modeShift) + _newTightness * _modeShift;
|
||||
|
|
|
@ -89,7 +89,7 @@ private:
|
|||
glm::vec3 _position;
|
||||
glm::vec3 _idealPosition;
|
||||
glm::vec3 _targetPosition;
|
||||
float _fieldOfView;
|
||||
float _fieldOfView; // degrees
|
||||
float _aspectRatio;
|
||||
float _nearClip;
|
||||
float _farClip;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "ClipboardScriptingInterface.h"
|
||||
|
||||
ClipboardScriptingInterface::ClipboardScriptingInterface() {
|
||||
connect(this, SIGNAL(readyToImport()), Application::getInstance(), SLOT(importVoxels()));
|
||||
}
|
||||
|
||||
void ClipboardScriptingInterface::cutVoxel(const VoxelDetail& sourceVoxel) {
|
||||
|
@ -70,12 +71,17 @@ void ClipboardScriptingInterface::exportVoxel(float x, float y, float z, float s
|
|||
z / (float)TREE_SCALE,
|
||||
s / (float)TREE_SCALE };
|
||||
|
||||
QMetaObject::invokeMethod(Application::getInstance(), "exportVoxels",
|
||||
Q_ARG(const VoxelDetail&, sourceVoxel));
|
||||
Application::getInstance()->exportVoxels(sourceVoxel);
|
||||
}
|
||||
|
||||
void ClipboardScriptingInterface::importVoxels() {
|
||||
QMetaObject::invokeMethod(Application::getInstance(), "importVoxels");
|
||||
bool ClipboardScriptingInterface::importVoxels() {
|
||||
qDebug() << "[DEBUG] Importing ... ";
|
||||
QEventLoop loop;
|
||||
connect(Application::getInstance(), SIGNAL(importDone()), &loop, SLOT(quit()));
|
||||
emit readyToImport();
|
||||
loop.exec();
|
||||
|
||||
return Application::getInstance()->getImportSucceded();
|
||||
}
|
||||
|
||||
void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) {
|
||||
|
|
|
@ -18,6 +18,9 @@ class ClipboardScriptingInterface : public QObject {
|
|||
public:
|
||||
ClipboardScriptingInterface();
|
||||
|
||||
signals:
|
||||
void readyToImport();
|
||||
|
||||
public slots:
|
||||
void cutVoxel(const VoxelDetail& sourceVoxel);
|
||||
void cutVoxel(float x, float y, float z, float s);
|
||||
|
@ -34,7 +37,7 @@ public slots:
|
|||
void exportVoxel(const VoxelDetail& sourceVoxel);
|
||||
void exportVoxel(float x, float y, float z, float s);
|
||||
|
||||
void importVoxels();
|
||||
bool importVoxels();
|
||||
|
||||
void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec);
|
||||
void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec);
|
||||
|
|
|
@ -237,8 +237,8 @@ void Environment::renderAtmosphere(Camera& camera, const EnvironmentData& data)
|
|||
program->setUniformValue(locations[INNER_RADIUS_LOCATION], data.getAtmosphereInnerRadius());
|
||||
program->setUniformValue(locations[KR_ESUN_LOCATION], data.getRayleighScattering() * data.getSunBrightness());
|
||||
program->setUniformValue(locations[KM_ESUN_LOCATION], data.getMieScattering() * data.getSunBrightness());
|
||||
program->setUniformValue(locations[KR_4PI_LOCATION], data.getRayleighScattering() * 4.0f * PIf);
|
||||
program->setUniformValue(locations[KM_4PI_LOCATION], data.getMieScattering() * 4.0f * PIf);
|
||||
program->setUniformValue(locations[KR_4PI_LOCATION], data.getRayleighScattering() * 4.0f * PI);
|
||||
program->setUniformValue(locations[KM_4PI_LOCATION], data.getMieScattering() * 4.0f * PI);
|
||||
program->setUniformValue(locations[SCALE_LOCATION], 1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius()));
|
||||
program->setUniformValue(locations[SCALE_DEPTH_LOCATION], 0.25f);
|
||||
program->setUniformValue(locations[SCALE_OVER_SCALE_DEPTH_LOCATION],
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <QWindow>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <XmppClient.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
@ -66,7 +67,7 @@ Menu::Menu() :
|
|||
_faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION),
|
||||
_frustumDrawMode(FRUSTUM_DRAW_MODE_ALL),
|
||||
_viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET),
|
||||
_voxelStatsDialog(NULL),
|
||||
_octreeStatsDialog(NULL),
|
||||
_lodToolsDialog(NULL),
|
||||
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM),
|
||||
_voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
|
||||
|
@ -164,6 +165,19 @@ Menu::Menu() :
|
|||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0, this, SLOT(showMetavoxelEditor()));
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::FstUploader, 0, Application::getInstance(), SLOT(uploadFST()));
|
||||
|
||||
_chatAction = addActionToQMenuAndActionHash(toolsMenu,
|
||||
MenuOption::Chat,
|
||||
Qt::Key_Return,
|
||||
this,
|
||||
SLOT(showChat()));
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
toggleChat();
|
||||
connect(&xmppClient, SIGNAL(connected()), this, SLOT(toggleChat()));
|
||||
connect(&xmppClient, SIGNAL(disconnected()), this, SLOT(toggleChat()));
|
||||
#else
|
||||
_chatAction->setEnabled(false);
|
||||
#endif
|
||||
|
||||
QMenu* viewMenu = addMenu("View");
|
||||
|
||||
|
@ -215,7 +229,7 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true);
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails()));
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::VoxelStats, 0, this, SLOT(voxelStatsDetails()));
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails()));
|
||||
|
||||
QMenu* developerMenu = addMenu("Developer");
|
||||
|
||||
|
@ -343,7 +357,7 @@ Menu::Menu() :
|
|||
|
||||
Menu::~Menu() {
|
||||
bandwidthDetailsClosed();
|
||||
voxelStatsDetailsClosed();
|
||||
octreeStatsDetailsClosed();
|
||||
}
|
||||
|
||||
void Menu::loadSettings(QSettings* settings) {
|
||||
|
@ -701,8 +715,8 @@ void Menu::editPreferences() {
|
|||
form->addRow("Faceshift Eye Deflection:", faceshiftEyeDeflection);
|
||||
|
||||
QSpinBox* fieldOfView = new QSpinBox();
|
||||
fieldOfView->setMaximum(180);
|
||||
fieldOfView->setMinimum(1);
|
||||
fieldOfView->setMaximum(180.f);
|
||||
fieldOfView->setMinimum(1.f);
|
||||
fieldOfView->setValue(_fieldOfView);
|
||||
form->addRow("Vertical Field of View (Degrees):", fieldOfView);
|
||||
|
||||
|
@ -1023,6 +1037,30 @@ void Menu::showMetavoxelEditor() {
|
|||
_MetavoxelEditor->raise();
|
||||
}
|
||||
|
||||
void Menu::showChat() {
|
||||
if (!_chatWindow) {
|
||||
_chatWindow = new ChatWindow();
|
||||
QMainWindow* mainWindow = Application::getInstance()->getWindow();
|
||||
_chatWindow->setGeometry(mainWindow->width() - _chatWindow->width(),
|
||||
mainWindow->geometry().y(),
|
||||
_chatWindow->width(),
|
||||
mainWindow->height());
|
||||
}
|
||||
if (!_chatWindow->isVisible()) {
|
||||
_chatWindow->show();
|
||||
}
|
||||
_chatWindow->raise();
|
||||
}
|
||||
|
||||
void Menu::toggleChat() {
|
||||
#ifdef HAVE_QXMPP
|
||||
_chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected());
|
||||
if (!_chatAction->isEnabled() && _chatWindow) {
|
||||
_chatWindow->close();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Menu::audioMuteToggled() {
|
||||
QAction *muteAction = _actionHash.value(MenuOption::MuteAudio);
|
||||
muteAction->setChecked(Application::getInstance()->getAudio()->getMuted());
|
||||
|
@ -1035,23 +1073,57 @@ void Menu::bandwidthDetailsClosed() {
|
|||
}
|
||||
}
|
||||
|
||||
void Menu::voxelStatsDetails() {
|
||||
if (!_voxelStatsDialog) {
|
||||
_voxelStatsDialog = new VoxelStatsDialog(Application::getInstance()->getGLWidget(),
|
||||
void Menu::octreeStatsDetails() {
|
||||
if (!_octreeStatsDialog) {
|
||||
_octreeStatsDialog = new OctreeStatsDialog(Application::getInstance()->getGLWidget(),
|
||||
Application::getInstance()->getOcteeSceneStats());
|
||||
connect(_voxelStatsDialog, SIGNAL(closed()), SLOT(voxelStatsDetailsClosed()));
|
||||
_voxelStatsDialog->show();
|
||||
connect(_octreeStatsDialog, SIGNAL(closed()), SLOT(octreeStatsDetailsClosed()));
|
||||
_octreeStatsDialog->show();
|
||||
}
|
||||
_voxelStatsDialog->raise();
|
||||
_octreeStatsDialog->raise();
|
||||
}
|
||||
|
||||
void Menu::voxelStatsDetailsClosed() {
|
||||
if (_voxelStatsDialog) {
|
||||
delete _voxelStatsDialog;
|
||||
_voxelStatsDialog = NULL;
|
||||
void Menu::octreeStatsDetailsClosed() {
|
||||
if (_octreeStatsDialog) {
|
||||
delete _octreeStatsDialog;
|
||||
_octreeStatsDialog = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
QString Menu::getLODFeedbackText() {
|
||||
// determine granularity feedback
|
||||
int boundaryLevelAdjust = getBoundaryLevelAdjust();
|
||||
QString granularityFeedback;
|
||||
|
||||
switch (boundaryLevelAdjust) {
|
||||
case 0: {
|
||||
granularityFeedback = QString("at standard granularity.");
|
||||
} break;
|
||||
case 1: {
|
||||
granularityFeedback = QString("at half of standard granularity.");
|
||||
} break;
|
||||
case 2: {
|
||||
granularityFeedback = QString("at a third of standard granularity.");
|
||||
} break;
|
||||
default: {
|
||||
granularityFeedback = QString("at 1/%1th of standard granularity.").arg(boundaryLevelAdjust + 1);
|
||||
} break;
|
||||
}
|
||||
|
||||
// distance feedback
|
||||
float voxelSizeScale = getVoxelSizeScale();
|
||||
float relativeToDefault = voxelSizeScale / DEFAULT_OCTREE_SIZE_SCALE;
|
||||
QString result;
|
||||
if (relativeToDefault > 1.01) {
|
||||
result = QString("%1 further %2").arg(relativeToDefault,8,'f',2).arg(granularityFeedback);
|
||||
} else if (relativeToDefault > 0.99) {
|
||||
result = QString("the default distance %1").arg(granularityFeedback);
|
||||
} else {
|
||||
result = QString("%1 of default %2").arg(relativeToDefault,8,'f',3).arg(granularityFeedback);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Menu::autoAdjustLOD(float currentFPS) {
|
||||
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't
|
||||
// really want to count them in our average, so we will ignore the real frame rates and stuff
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <OctreeConstants.h>
|
||||
|
||||
#include "ui/PreferencesDialog.h"
|
||||
#include <ui/ChatWindow.h>
|
||||
|
||||
const float ADJUST_LOD_DOWN_FPS = 40.0;
|
||||
const float ADJUST_LOD_UP_FPS = 55.0;
|
||||
|
@ -55,7 +56,8 @@ class QSettings;
|
|||
class BandwidthDialog;
|
||||
class LodToolsDialog;
|
||||
class MetavoxelEditor;
|
||||
class VoxelStatsDialog;
|
||||
class ChatWindow;
|
||||
class OctreeStatsDialog;
|
||||
class MenuItemProperties;
|
||||
|
||||
class Menu : public QMenuBar {
|
||||
|
@ -77,7 +79,7 @@ public:
|
|||
BandwidthDialog* getBandwidthDialog() const { return _bandwidthDialog; }
|
||||
FrustumDrawMode getFrustumDrawMode() const { return _frustumDrawMode; }
|
||||
ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; }
|
||||
VoxelStatsDialog* getVoxelStatsDialog() const { return _voxelStatsDialog; }
|
||||
OctreeStatsDialog* getOctreeStatsDialog() const { return _octreeStatsDialog; }
|
||||
LodToolsDialog* getLodToolsDialog() const { return _lodToolsDialog; }
|
||||
int getMaxVoxels() const { return _maxVoxels; }
|
||||
QAction* getUseVoxelShader() const { return _useVoxelShader; }
|
||||
|
@ -85,6 +87,7 @@ public:
|
|||
void handleViewFrustumOffsetKeyModifier(int key);
|
||||
|
||||
// User Tweakable LOD Items
|
||||
QString getLODFeedbackText();
|
||||
void autoAdjustLOD(float currentFPS);
|
||||
void setVoxelSizeScale(float sizeScale);
|
||||
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
||||
|
@ -116,7 +119,7 @@ public slots:
|
|||
|
||||
void loginForCurrentDomain();
|
||||
void bandwidthDetails();
|
||||
void voxelStatsDetails();
|
||||
void octreeStatsDetails();
|
||||
void lodTools();
|
||||
void loadSettings(QSettings* settings = NULL);
|
||||
void saveSettings(QSettings* settings = NULL);
|
||||
|
@ -140,11 +143,13 @@ private slots:
|
|||
void goToDomainDialog();
|
||||
void goToLocation();
|
||||
void bandwidthDetailsClosed();
|
||||
void voxelStatsDetailsClosed();
|
||||
void octreeStatsDetailsClosed();
|
||||
void lodToolsClosed();
|
||||
void cycleFrustumRenderMode();
|
||||
void runTests();
|
||||
void showMetavoxelEditor();
|
||||
void showChat();
|
||||
void toggleChat();
|
||||
void audioMuteToggled();
|
||||
|
||||
private:
|
||||
|
@ -192,7 +197,8 @@ private:
|
|||
FrustumDrawMode _frustumDrawMode;
|
||||
ViewFrustumOffset _viewFrustumOffset;
|
||||
QPointer<MetavoxelEditor> _MetavoxelEditor;
|
||||
VoxelStatsDialog* _voxelStatsDialog;
|
||||
QPointer<ChatWindow> _chatWindow;
|
||||
OctreeStatsDialog* _octreeStatsDialog;
|
||||
LodToolsDialog* _lodToolsDialog;
|
||||
int _maxVoxels;
|
||||
float _voxelSizeScale;
|
||||
|
@ -205,6 +211,7 @@ private:
|
|||
SimpleMovingAverage _fpsAverage;
|
||||
QAction* _loginAction;
|
||||
QPointer<PreferencesDialog> _preferencesDialog;
|
||||
QAction* _chatAction;
|
||||
};
|
||||
|
||||
namespace MenuOption {
|
||||
|
@ -258,6 +265,7 @@ namespace MenuOption {
|
|||
const QString Logout = "Logout";
|
||||
const QString LookAtVectors = "Look-at Vectors";
|
||||
const QString MetavoxelEditor = "Metavoxel Editor...";
|
||||
const QString Chat = "Chat...";
|
||||
const QString Metavoxels = "Metavoxels";
|
||||
const QString Mirror = "Mirror";
|
||||
const QString MoveWithLean = "Move with Lean";
|
||||
|
@ -292,7 +300,7 @@ namespace MenuOption {
|
|||
const QString Quit = "Quit";
|
||||
const QString Voxels = "Voxels";
|
||||
const QString VoxelMode = "Cycle Voxel Mode";
|
||||
const QString VoxelStats = "Voxel Stats";
|
||||
const QString OctreeStats = "Voxel and Particle Statistics";
|
||||
const QString VoxelTextures = "Voxel Textures";
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <QMutexLocker>
|
||||
#include <QtDebug>
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <MetavoxelUtil.h>
|
||||
|
@ -18,6 +20,7 @@
|
|||
#include "MetavoxelSystem.h"
|
||||
#include "renderer/Model.h"
|
||||
|
||||
REGISTER_META_OBJECT(SphereRenderer)
|
||||
REGISTER_META_OBJECT(StaticModelRenderer)
|
||||
|
||||
ProgramObject MetavoxelSystem::_program;
|
||||
|
@ -41,6 +44,31 @@ void MetavoxelSystem::init() {
|
|||
connect(NodeList::getInstance(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachClient(const SharedNodePointer&)));
|
||||
}
|
||||
|
||||
SharedObjectPointer MetavoxelSystem::findFirstRaySpannerIntersection(
|
||||
const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, float& distance) {
|
||||
SharedObjectPointer closestSpanner;
|
||||
float closestDistance = FLT_MAX;
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
float clientDistance;
|
||||
SharedObjectPointer clientSpanner = client->getData().findFirstRaySpannerIntersection(
|
||||
origin, direction, attribute, clientDistance);
|
||||
if (clientSpanner && clientDistance < closestDistance) {
|
||||
closestSpanner = clientSpanner;
|
||||
closestDistance = clientDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (closestSpanner) {
|
||||
distance = closestDistance;
|
||||
}
|
||||
return closestSpanner;
|
||||
}
|
||||
|
||||
void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit) {
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
|
@ -57,13 +85,14 @@ void MetavoxelSystem::simulate(float deltaTime) {
|
|||
// simulate the clients
|
||||
_points.clear();
|
||||
_simulateVisitor.setDeltaTime(deltaTime);
|
||||
_simulateVisitor.setOrder(-Application::getInstance()->getViewFrustum()->getDirection());
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
client->simulate(deltaTime);
|
||||
client->getData().guide(_simulateVisitor);
|
||||
client->guide(_simulateVisitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +134,7 @@ void MetavoxelSystem::render() {
|
|||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
|
||||
|
||||
|
||||
glDrawArrays(GL_POINTS, 0, _points.size());
|
||||
|
||||
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
|
||||
|
@ -123,7 +152,7 @@ void MetavoxelSystem::render() {
|
|||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
client->getData().guide(_renderVisitor);
|
||||
client->guide(_renderVisitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,15 +172,16 @@ MetavoxelSystem::SimulateVisitor::SimulateVisitor(QVector<Point>& points) :
|
|||
_points(points) {
|
||||
}
|
||||
|
||||
void MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner) {
|
||||
bool MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner) {
|
||||
spanner->getRenderer()->simulate(_deltaTime);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) {
|
||||
int MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) {
|
||||
SpannerVisitor::visit(info);
|
||||
|
||||
if (!info.isLeaf) {
|
||||
return true;
|
||||
return _order;
|
||||
}
|
||||
QRgb color = info.inputValues.at(0).getInlineValue<QRgb>();
|
||||
QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>();
|
||||
|
@ -161,15 +191,16 @@ bool MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) {
|
|||
{ qRed(color), qGreen(color), qBlue(color), alpha }, { qRed(normal), qGreen(normal), qBlue(normal) } };
|
||||
_points.append(point);
|
||||
}
|
||||
return false;
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
MetavoxelSystem::RenderVisitor::RenderVisitor() :
|
||||
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()) {
|
||||
}
|
||||
|
||||
void MetavoxelSystem::RenderVisitor::visit(Spanner* spanner) {
|
||||
bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner) {
|
||||
spanner->getRenderer()->render(1.0f);
|
||||
return true;
|
||||
}
|
||||
|
||||
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) :
|
||||
|
@ -178,11 +209,16 @@ MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) :
|
|||
|
||||
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&)));
|
||||
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
|
||||
connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int)));
|
||||
connect(&_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int)));
|
||||
|
||||
// insert the baseline send record
|
||||
SendRecord sendRecord = { 0 };
|
||||
_sendRecords.append(sendRecord);
|
||||
|
||||
// insert the baseline receive record
|
||||
ReceiveRecord record = { 0, _data };
|
||||
_receiveRecords.append(record);
|
||||
ReceiveRecord receiveRecord = { 0, _data };
|
||||
_receiveRecords.append(receiveRecord);
|
||||
}
|
||||
|
||||
MetavoxelClient::~MetavoxelClient() {
|
||||
|
@ -192,9 +228,19 @@ MetavoxelClient::~MetavoxelClient() {
|
|||
_sequencer.endPacket();
|
||||
}
|
||||
|
||||
static MetavoxelLOD getLOD() {
|
||||
const float FIXED_LOD_THRESHOLD = 0.01f;
|
||||
return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD);
|
||||
}
|
||||
|
||||
void MetavoxelClient::guide(MetavoxelVisitor& visitor) {
|
||||
visitor.setLOD(getLOD());
|
||||
_data.guide(visitor);
|
||||
}
|
||||
|
||||
void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) {
|
||||
// apply immediately to local tree
|
||||
edit.apply(_data);
|
||||
edit.apply(_data, _sequencer.getWeakSharedObjectHash());
|
||||
|
||||
// start sending it out
|
||||
_sequencer.sendHighPriorityMessage(QVariant::fromValue(edit));
|
||||
|
@ -202,9 +248,14 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) {
|
|||
|
||||
void MetavoxelClient::simulate(float deltaTime) {
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
ClientStateMessage state = { Application::getInstance()->getCamera()->getPosition() };
|
||||
|
||||
ClientStateMessage state = { getLOD() };
|
||||
out << QVariant::fromValue(state);
|
||||
_sequencer.endPacket();
|
||||
|
||||
// record the send
|
||||
SendRecord record = { _sequencer.getOutgoingPacketNumber(), state.lod };
|
||||
_sendRecords.append(record);
|
||||
}
|
||||
|
||||
int MetavoxelClient::parseData(const QByteArray& packet) {
|
||||
|
@ -223,17 +274,21 @@ void MetavoxelClient::readPacket(Bitstream& in) {
|
|||
handleMessage(message, in);
|
||||
|
||||
// record the receipt
|
||||
ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data };
|
||||
ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data, _sendRecords.first().lod };
|
||||
_receiveRecords.append(record);
|
||||
|
||||
// reapply local edits
|
||||
foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) {
|
||||
if (message.data.userType() == MetavoxelEditMessage::Type) {
|
||||
message.data.value<MetavoxelEditMessage>().apply(_data);
|
||||
message.data.value<MetavoxelEditMessage>().apply(_data, _sequencer.getWeakSharedObjectHash());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelClient::clearSendRecordsBefore(int index) {
|
||||
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
||||
}
|
||||
|
||||
void MetavoxelClient::clearReceiveRecordsBefore(int index) {
|
||||
_receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1);
|
||||
}
|
||||
|
@ -241,7 +296,7 @@ void MetavoxelClient::clearReceiveRecordsBefore(int index) {
|
|||
void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
||||
int userType = message.userType();
|
||||
if (userType == MetavoxelDeltaMessage::Type) {
|
||||
_data.readDelta(_receiveRecords.first().data, in);
|
||||
_data.readDelta(_receiveRecords.first().data, _receiveRecords.first().lod, in, _sendRecords.first().lod);
|
||||
|
||||
} else if (userType == QMetaType::QVariantList) {
|
||||
foreach (const QVariant& element, message.toList()) {
|
||||
|
@ -250,6 +305,26 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
|||
}
|
||||
}
|
||||
|
||||
SphereRenderer::SphereRenderer() {
|
||||
}
|
||||
|
||||
void SphereRenderer::render(float alpha) {
|
||||
Sphere* sphere = static_cast<Sphere*>(parent());
|
||||
const QColor& color = sphere->getColor();
|
||||
glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF() * alpha);
|
||||
|
||||
glPushMatrix();
|
||||
const glm::vec3& translation = sphere->getTranslation();
|
||||
glTranslatef(translation.x, translation.y, translation.z);
|
||||
glm::quat rotation = glm::quat(glm::radians(sphere->getRotation()));
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
|
||||
glutSolidSphere(sphere->getScale(), 10, 10);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
StaticModelRenderer::StaticModelRenderer() :
|
||||
_model(new Model(this)) {
|
||||
}
|
||||
|
@ -270,6 +345,14 @@ void StaticModelRenderer::init(Spanner* spanner) {
|
|||
}
|
||||
|
||||
void StaticModelRenderer::simulate(float deltaTime) {
|
||||
// update the bounds
|
||||
Box bounds;
|
||||
if (_model->isActive()) {
|
||||
const Extents& extents = _model->getGeometry()->getFBXGeometry().meshExtents;
|
||||
bounds = Box(extents.minimum, extents.maximum);
|
||||
}
|
||||
static_cast<StaticModel*>(parent())->setBounds(glm::translate(_model->getTranslation()) *
|
||||
glm::mat4_cast(_model->getRotation()) * glm::scale(_model->getScale()) * bounds);
|
||||
_model->simulate(deltaTime);
|
||||
}
|
||||
|
||||
|
@ -277,6 +360,10 @@ void StaticModelRenderer::render(float alpha) {
|
|||
_model->render(alpha);
|
||||
}
|
||||
|
||||
bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
|
||||
return _model->findRayIntersection(origin, direction, distance);
|
||||
}
|
||||
|
||||
void StaticModelRenderer::applyTranslation(const glm::vec3& translation) {
|
||||
_model->setTranslation(translation);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,9 @@ public:
|
|||
|
||||
void init();
|
||||
|
||||
SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
const AttributePointer& attribute, float& distance);
|
||||
|
||||
void applyEdit(const MetavoxelEditMessage& edit);
|
||||
|
||||
void simulate(float deltaTime);
|
||||
|
@ -57,18 +60,20 @@ private:
|
|||
public:
|
||||
SimulateVisitor(QVector<Point>& points);
|
||||
void setDeltaTime(float deltaTime) { _deltaTime = deltaTime; }
|
||||
virtual void visit(Spanner* spanner);
|
||||
virtual bool visit(MetavoxelInfo& info);
|
||||
void setOrder(const glm::vec3& direction) { _order = encodeOrder(direction); }
|
||||
virtual bool visit(Spanner* spanner);
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
QVector<Point>& _points;
|
||||
float _deltaTime;
|
||||
int _order;
|
||||
};
|
||||
|
||||
class RenderVisitor : public SpannerVisitor {
|
||||
public:
|
||||
RenderVisitor();
|
||||
virtual void visit(Spanner* spanner);
|
||||
virtual bool visit(Spanner* spanner);
|
||||
};
|
||||
|
||||
static ProgramObject _program;
|
||||
|
@ -91,6 +96,8 @@ public:
|
|||
|
||||
MetavoxelData& getData() { return _data; }
|
||||
|
||||
void guide(MetavoxelVisitor& visitor);
|
||||
|
||||
void applyEdit(const MetavoxelEditMessage& edit);
|
||||
|
||||
void simulate(float deltaTime);
|
||||
|
@ -103,16 +110,25 @@ private slots:
|
|||
|
||||
void readPacket(Bitstream& in);
|
||||
|
||||
void clearSendRecordsBefore(int index);
|
||||
|
||||
void clearReceiveRecordsBefore(int index);
|
||||
|
||||
private:
|
||||
|
||||
void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
class SendRecord {
|
||||
public:
|
||||
int packetNumber;
|
||||
MetavoxelLOD lod;
|
||||
};
|
||||
|
||||
class ReceiveRecord {
|
||||
public:
|
||||
int packetNumber;
|
||||
MetavoxelData data;
|
||||
MetavoxelLOD lod;
|
||||
};
|
||||
|
||||
SharedNodePointer _node;
|
||||
|
@ -121,9 +137,21 @@ private:
|
|||
|
||||
MetavoxelData _data;
|
||||
|
||||
QList<SendRecord> _sendRecords;
|
||||
QList<ReceiveRecord> _receiveRecords;
|
||||
};
|
||||
|
||||
/// Renders spheres.
|
||||
class SphereRenderer : public SpannerRenderer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE SphereRenderer();
|
||||
|
||||
virtual void render(float alpha);
|
||||
};
|
||||
|
||||
/// Renders static models.
|
||||
class StaticModelRenderer : public SpannerRenderer {
|
||||
Q_OBJECT
|
||||
|
@ -135,11 +163,12 @@ public:
|
|||
virtual void init(Spanner* spanner);
|
||||
virtual void simulate(float deltaTime);
|
||||
virtual void render(float alpha);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
|
||||
private slots:
|
||||
|
||||
void applyTranslation(const glm::vec3& translation);
|
||||
void applyRotation(const glm::vec3& rotation);
|
||||
void applyRotation(const glm::vec3& eulerAngles); // eulerAngles are in degrees
|
||||
void applyScale(float scale);
|
||||
void applyURL(const QUrl& url);
|
||||
|
||||
|
|
|
@ -30,9 +30,8 @@ bool Stars::setResolution(unsigned k) {
|
|||
}
|
||||
|
||||
void Stars::render(float fovY, float aspect, float nearZ, float alpha) {
|
||||
|
||||
// determine length of screen diagonal from quadrant height and aspect ratio
|
||||
float quadrantHeight = nearZ * tan(angleConvert<Degrees,Radians>(fovY) * 0.5f);
|
||||
float quadrantHeight = nearZ * tan(RADIANS_PER_DEGREE * fovY * 0.5f);
|
||||
float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect));
|
||||
|
||||
// determine fov angle in respect to the diagonal
|
||||
|
|
|
@ -68,19 +68,21 @@ void printVector(glm::vec3 vec) {
|
|||
printf("%4.2f, %4.2f, %4.2f\n", vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
||||
// Return the azimuth angle in degrees between two points.
|
||||
// Return the azimuth angle (in radians) between two points.
|
||||
float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos) {
|
||||
return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z) * 180.0f / PIf;
|
||||
return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z);
|
||||
}
|
||||
|
||||
// Return the angle in degrees between the head and an object in the scene. The value is zero if you are looking right at it. The angle is negative if the object is to your right.
|
||||
// Return the angle (in radians) between the head and an object in the scene.
|
||||
// The value is zero if you are looking right at it.
|
||||
// The angle is negative if the object is to your right.
|
||||
float angle_to(glm::vec3 head_pos, glm::vec3 source_pos, float render_yaw, float head_yaw) {
|
||||
return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z) * 180.0f / PIf + render_yaw + head_yaw;
|
||||
return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z) + render_yaw + head_yaw;
|
||||
}
|
||||
|
||||
// Helper function returns the positive angle in degrees between two 3D vectors
|
||||
// Helper function returns the positive angle (in radians) between two 3D vectors
|
||||
float angleBetween(const glm::vec3& v1, const glm::vec3& v2) {
|
||||
return acos((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2))) * 180.f / PIf;
|
||||
return acosf((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2)));
|
||||
}
|
||||
|
||||
// Helper function return the rotation from the first vector onto the second
|
||||
|
@ -90,7 +92,7 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
|
|||
return glm::quat();
|
||||
}
|
||||
glm::vec3 axis;
|
||||
if (angle > 179.99f) { // 180 degree rotation; must use another axis
|
||||
if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis
|
||||
axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
float axisLength = glm::length(axis);
|
||||
if (axisLength < EPSILON) { // parallel to x; y will work
|
||||
|
@ -314,7 +316,7 @@ float widthChar(float scale, int mono, char ch) {
|
|||
return textRenderer(mono)->computeWidth(ch) * (scale / 0.10);
|
||||
}
|
||||
|
||||
void drawText(int x, int y, float scale, float rotate, int mono,
|
||||
void drawText(int x, int y, float scale, float radians, int mono,
|
||||
char const* string, const float* color) {
|
||||
//
|
||||
// Draws text on screen as stroked so it can be resized
|
||||
|
@ -322,16 +324,16 @@ void drawText(int x, int y, float scale, float rotate, int mono,
|
|||
glPushMatrix();
|
||||
glTranslatef(static_cast<float>(x), static_cast<float>(y), 0.0f);
|
||||
glColor3fv(color);
|
||||
glRotated(rotate,0,0,1);
|
||||
glScalef(scale / 0.10, scale / 0.10, 1.0);
|
||||
glRotated(double(radians * DEGREES_PER_RADIAN), 0.0, 0.0, 1.0);
|
||||
glScalef(scale / 0.1f, scale / 0.1f, 1.f);
|
||||
textRenderer(mono)->draw(0, 0, string);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, glm::vec3 vec, float r, float g, float b) {
|
||||
void drawvec3(int x, int y, float scale, float radians, float thick, int mono, glm::vec3 vec, float r, float g, float b) {
|
||||
//
|
||||
// Draws text on screen as stroked so it can be resized
|
||||
// Draws vec3 on screen as stroked so it can be resized
|
||||
//
|
||||
char vectext[20];
|
||||
sprintf(vectext,"%3.1f,%3.1f,%3.1f", vec.x, vec.y, vec.z);
|
||||
|
@ -339,10 +341,10 @@ void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, gl
|
|||
glPushMatrix();
|
||||
glTranslatef(static_cast<float>(x), static_cast<float>(y), 0);
|
||||
glColor3f(r,g,b);
|
||||
glRotated(180+rotate,0,0,1);
|
||||
glRotated(180,0,1,0);
|
||||
glRotated(180.0 + double(radians * DEGREES_PER_RADIAN), 0.0, 0.0, 1.0);
|
||||
glRotated(180.0, 0.0, 1.0, 0.0);
|
||||
glLineWidth(thick);
|
||||
glScalef(scale, scale, 1.0);
|
||||
glScalef(scale, scale, 1.f);
|
||||
len = (int) strlen(vectext);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!mono) glutStrokeCharacter(GLUT_STROKE_ROMAN, int(vectext[i]));
|
||||
|
@ -371,9 +373,9 @@ void renderSphereOutline(glm::vec3 position, float radius, int numSides, glm::ve
|
|||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for (int i=0; i<numSides+1; i++) {
|
||||
float r = ((float)i / (float)numSides) * PIf * 2.0;
|
||||
float s = radius * sin(r);
|
||||
float c = radius * cos(r);
|
||||
float r = ((float)i / (float)numSides) * TWO_PI;
|
||||
float s = radius * sinf(r);
|
||||
float c = radius * cosf(r);
|
||||
|
||||
glVertex3f
|
||||
(
|
||||
|
@ -394,9 +396,9 @@ void renderCircle(glm::vec3 position, float radius, glm::vec3 surfaceNormal, int
|
|||
glBegin(GL_LINE_STRIP);
|
||||
|
||||
for (int i=0; i<numSides+1; i++) {
|
||||
float r = ((float)i / (float)numSides) * PIf * 2.0;
|
||||
float s = radius * sin(r);
|
||||
float c = radius * cos(r);
|
||||
float r = ((float)i / (float)numSides) * TWO_PI;
|
||||
float s = radius * sinf(r);
|
||||
float c = radius * cosf(r);
|
||||
glVertex3f
|
||||
(
|
||||
position.x + perp1.x * s + perp2.x * c,
|
||||
|
@ -440,12 +442,12 @@ void renderRoundedCornersRect(int x, int y, int width, int height, int radius, i
|
|||
numPointsCorner = MAX_POINTS_CORNER;
|
||||
}
|
||||
|
||||
// Precompute sin and cos for [0, pi/2) for the number of points (numPointCorner)
|
||||
// Precompute sin and cos for [0, PI/2) for the number of points (numPointCorner)
|
||||
double radiusTimesSin[MAX_POINTS_CORNER];
|
||||
double radiusTimesCos[MAX_POINTS_CORNER];
|
||||
int i = 0;
|
||||
for (int i = 0; i < numPointsCorner; i++) {
|
||||
double t = i * PIf / (2.0f * (numPointsCorner - 1));
|
||||
double t = (double)i * (double)PI_OVER_TWO / (double)(numPointsCorner - 1);
|
||||
radiusTimesSin[i] = radius * sin(t);
|
||||
radiusTimesCos[i] = radius * cos(t);
|
||||
}
|
||||
|
|
|
@ -31,10 +31,10 @@ void renderWorldBox();
|
|||
int widthText(float scale, int mono, char const* string);
|
||||
float widthChar(float scale, int mono, char ch);
|
||||
|
||||
void drawText(int x, int y, float scale, float rotate, int mono,
|
||||
void drawText(int x, int y, float scale, float radians, int mono,
|
||||
char const* string, const float* color);
|
||||
|
||||
void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, glm::vec3 vec,
|
||||
void drawvec3(int x, int y, float scale, float radians, float thick, int mono, glm::vec3 vec,
|
||||
float r=1.0, float g=1.0, float b=1.0);
|
||||
|
||||
void drawVector(glm::vec3* vector);
|
||||
|
|
|
@ -1177,8 +1177,6 @@ void VoxelSystem::init() {
|
|||
}
|
||||
|
||||
void VoxelSystem::changeTree(VoxelTree* newTree) {
|
||||
disconnect(_tree, 0, this, 0);
|
||||
|
||||
_tree = newTree;
|
||||
|
||||
_tree->setDirtyBit();
|
||||
|
|
69
interface/src/XmppClient.cpp
Normal file
69
interface/src/XmppClient.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// XmppClient.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Dimitar Dobrev on 10/3/14
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
|
||||
#include <AccountManager.h>
|
||||
|
||||
#include "XmppClient.h"
|
||||
|
||||
const QString DEFAULT_XMPP_SERVER = "chat.highfidelity.io";
|
||||
const QString DEFAULT_CHAT_ROOM = "public@public-chat.highfidelity.io";
|
||||
|
||||
XmppClient::XmppClient() :
|
||||
_xmppClient(),
|
||||
_xmppMUCManager()
|
||||
{
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
connect(&accountManager, SIGNAL(accessTokenChanged()), this, SLOT(connectToServer()));
|
||||
connect(&accountManager, SIGNAL(logoutComplete()), this, SLOT(disconnectFromServer()));
|
||||
}
|
||||
|
||||
XmppClient& XmppClient::getInstance() {
|
||||
static XmppClient sharedInstance;
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
void XmppClient::xmppConnected() {
|
||||
_publicChatRoom = _xmppMUCManager.addRoom(DEFAULT_CHAT_ROOM);
|
||||
_publicChatRoom->setNickName(AccountManager::getInstance().getUsername());
|
||||
_publicChatRoom->join();
|
||||
}
|
||||
|
||||
void XmppClient::xmppError(QXmppClient::Error error) {
|
||||
qDebug() << "Error connnecting to XMPP for user " << AccountManager::getInstance().getUsername() << ": " << error;
|
||||
}
|
||||
|
||||
void XmppClient::connectToServer() {
|
||||
disconnectFromServer();
|
||||
|
||||
if (_xmppClient.addExtension(&_xmppMUCManager)) {
|
||||
connect(&_xmppClient, SIGNAL(connected()), this, SLOT(xmppConnected()));
|
||||
connect(&_xmppClient, SIGNAL(error(QXmppClient::Error)), this, SLOT(xmppError(QXmppClient::Error)));
|
||||
}
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
QString user = accountManager.getUsername();
|
||||
const QString& password = accountManager.getXMPPPassword();
|
||||
_xmppClient.connectToServer(user + "@" + DEFAULT_XMPP_SERVER, password);
|
||||
}
|
||||
|
||||
void XmppClient::disconnectFromServer() {
|
||||
if (_xmppClient.isConnected()) {
|
||||
_xmppClient.disconnectFromServer();
|
||||
}
|
||||
}
|
||||
|
||||
XmppClient::XmppClient(const XmppClient& other) {
|
||||
Q_UNUSED(other);
|
||||
}
|
||||
|
||||
void XmppClient::operator =(XmppClient const& other) {
|
||||
Q_UNUSED(other);
|
||||
}
|
||||
|
||||
#endif
|
47
interface/src/XmppClient.h
Normal file
47
interface/src/XmppClient.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// XmppClient.h
|
||||
// interface
|
||||
//
|
||||
// Created by Dimitar Dobrev on 10/3/14
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
|
||||
#ifndef __interface__XmppClient__
|
||||
#define __interface__XmppClient__
|
||||
|
||||
#include <QObject>
|
||||
#include <QXmppClient.h>
|
||||
#include <QXmppMucManager.h>
|
||||
|
||||
/// Generalized threaded processor for handling received inbound packets.
|
||||
class XmppClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static XmppClient& getInstance();
|
||||
|
||||
QXmppClient& getXMPPClient() { return _xmppClient; }
|
||||
const QXmppMucRoom* getPublicChatRoom() const { return _publicChatRoom; }
|
||||
|
||||
private slots:
|
||||
void xmppConnected();
|
||||
void xmppError(QXmppClient::Error error);
|
||||
|
||||
void connectToServer();
|
||||
void disconnectFromServer();
|
||||
|
||||
private:
|
||||
XmppClient();
|
||||
XmppClient(XmppClient const& other); // not implemented
|
||||
void operator=(XmppClient const& other); // not implemented
|
||||
|
||||
QXmppClient _xmppClient;
|
||||
QXmppMucManager _xmppMUCManager;
|
||||
QXmppMucRoom* _publicChatRoom;
|
||||
};
|
||||
|
||||
#endif // __interface__XmppClient__
|
||||
|
||||
#endif
|
|
@ -31,28 +31,6 @@
|
|||
using namespace std;
|
||||
|
||||
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
||||
const float YAW_MAG = 500.0f;
|
||||
const float MY_HAND_HOLDING_PULL = 0.2f;
|
||||
const float YOUR_HAND_HOLDING_PULL = 1.0f;
|
||||
const float BODY_SPRING_DEFAULT_TIGHTNESS = 1000.0f;
|
||||
const float BODY_SPRING_FORCE = 300.0f;
|
||||
const float BODY_SPRING_DECAY = 16.0f;
|
||||
const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions
|
||||
const float COLLISION_BODY_FORCE = 30.0f; // pertains to avatar-to-avatar collisions
|
||||
const float HEAD_ROTATION_SCALE = 0.70f;
|
||||
const float HEAD_ROLL_SCALE = 0.40f;
|
||||
const float HEAD_MAX_PITCH = 45;
|
||||
const float HEAD_MIN_PITCH = -45;
|
||||
const float HEAD_MAX_YAW = 85;
|
||||
const float HEAD_MIN_YAW = -85;
|
||||
const float AVATAR_BRAKING_STRENGTH = 40.0f;
|
||||
const float MOUSE_RAY_TOUCH_RANGE = 0.01f;
|
||||
const float FLOATING_HEIGHT = 0.13f;
|
||||
const bool USING_HEAD_LEAN = false;
|
||||
const float LEAN_SENSITIVITY = 0.15f;
|
||||
const float LEAN_MAX = 0.45f;
|
||||
const float LEAN_AVERAGING = 10.0f;
|
||||
const float HEAD_RATE_MAX = 50.f;
|
||||
const int NUM_BODY_CONE_SIDES = 9;
|
||||
const float CHAT_MESSAGE_SCALE = 0.0015f;
|
||||
const float CHAT_MESSAGE_HEIGHT = 0.1f;
|
||||
|
@ -131,9 +109,6 @@ void Avatar::simulate(float deltaTime) {
|
|||
_shouldRenderBillboard = true;
|
||||
}
|
||||
|
||||
// copy velocity so we can use it later for acceleration
|
||||
glm::vec3 oldVelocity = getVelocity();
|
||||
|
||||
getHand()->simulate(deltaTime, false);
|
||||
_skeletonModel.setLODDistance(getLODDistance());
|
||||
|
||||
|
@ -214,7 +189,7 @@ void Avatar::render(bool forShadowMap) {
|
|||
{
|
||||
// glow when moving in the distance
|
||||
|
||||
const float GLOW_DISTANCE = 5.0f;
|
||||
const float GLOW_DISTANCE = 20.0f;
|
||||
Glower glower(_moving && lengthToTarget > GLOW_DISTANCE && !forShadowMap ? 1.0f : 0.0f);
|
||||
|
||||
// render body
|
||||
|
@ -229,8 +204,8 @@ void Avatar::render(bool forShadowMap) {
|
|||
}
|
||||
|
||||
// render voice intensity sphere for avatars that are farther away
|
||||
const float MAX_SPHERE_ANGLE = 10.f;
|
||||
const float MIN_SPHERE_ANGLE = 1.f;
|
||||
const float MAX_SPHERE_ANGLE = 10.f * RADIANS_PER_DEGREE;
|
||||
const float MIN_SPHERE_ANGLE = 1.f * RADIANS_PER_DEGREE;
|
||||
const float MIN_SPHERE_SIZE = 0.01f;
|
||||
const float SPHERE_LOUDNESS_SCALING = 0.0005f;
|
||||
const float SPHERE_COLOR[] = { 0.5f, 0.8f, 0.8f };
|
||||
|
@ -267,12 +242,12 @@ void Avatar::render(bool forShadowMap) {
|
|||
glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z);
|
||||
glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation();
|
||||
glm::vec3 chatAxis = glm::axis(chatRotation);
|
||||
glRotatef(glm::angle(chatRotation), chatAxis.x, chatAxis.y, chatAxis.z);
|
||||
glRotatef(glm::degrees(glm::angle(chatRotation)), chatAxis.x, chatAxis.y, chatAxis.z);
|
||||
|
||||
|
||||
glColor3f(0, 0.8f, 0);
|
||||
glRotatef(180, 0, 1, 0);
|
||||
glRotatef(180, 0, 0, 1);
|
||||
glColor3f(0.f, 0.8f, 0.f);
|
||||
glRotatef(180.f, 0.f, 1.f, 0.f);
|
||||
glRotatef(180.f, 0.f, 0.f, 1.f);
|
||||
glScalef(_scale * CHAT_MESSAGE_SCALE, _scale * CHAT_MESSAGE_SCALE, 1.0f);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
|
@ -288,7 +263,7 @@ void Avatar::render(bool forShadowMap) {
|
|||
_chatMessage[lastIndex] = '\0';
|
||||
textRenderer(CHAT)->draw(-width / 2.0f, 0, _chatMessage.c_str());
|
||||
_chatMessage[lastIndex] = lastChar;
|
||||
glColor3f(0, 1, 0);
|
||||
glColor3f(0.f, 1.f, 0.f);
|
||||
textRenderer(CHAT)->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex);
|
||||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
|
@ -301,12 +276,12 @@ void Avatar::render(bool forShadowMap) {
|
|||
glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
||||
glm::quat orientation = getOrientation();
|
||||
glm::vec3 currentUp = orientation * IDENTITY_UP;
|
||||
float angle = glm::degrees(acosf(glm::clamp(glm::dot(currentUp, _worldUpDirection), -1.0f, 1.0f)));
|
||||
float angle = acosf(glm::clamp(glm::dot(currentUp, _worldUpDirection), -1.0f, 1.0f));
|
||||
if (angle < EPSILON) {
|
||||
return glm::quat();
|
||||
}
|
||||
glm::vec3 axis;
|
||||
if (angle > 179.99f) { // 180 degree rotation; must use another axis
|
||||
if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis
|
||||
axis = orientation * IDENTITY_RIGHT;
|
||||
} else {
|
||||
axis = glm::normalize(glm::cross(currentUp, _worldUpDirection));
|
||||
|
@ -356,9 +331,9 @@ void Avatar::renderBillboard() {
|
|||
// rotate about vertical to face the camera
|
||||
glm::quat rotation = getOrientation();
|
||||
glm::vec3 cameraVector = glm::inverse(rotation) * (Application::getInstance()->getCamera()->getPosition() - _position);
|
||||
rotation = rotation * glm::angleAxis(glm::degrees(atan2f(-cameraVector.x, -cameraVector.z)), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
rotation = rotation * glm::angleAxis(atan2f(-cameraVector.x, -cameraVector.z), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
// compute the size from the billboard camera parameters and scale
|
||||
float size = _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));
|
||||
|
@ -404,7 +379,7 @@ void Avatar::renderDisplayName() {
|
|||
// we need "always facing camera": we must remove the camera rotation from the stack
|
||||
glm::quat rotation = Application::getInstance()->getCamera()->getRotation();
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
// We need to compute the scale factor such as the text remains with fixed size respect to window coordinates
|
||||
// We project a unit vector and check the difference in screen coordinates, to check which is the
|
||||
|
@ -662,15 +637,15 @@ void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2,
|
|||
glm::vec3 perpCos = glm::normalize(glm::cross(axis, perpSin));
|
||||
perpSin = glm::cross(perpCos, axis);
|
||||
|
||||
float anglea = 0.0;
|
||||
float angleb = 0.0;
|
||||
float anglea = 0.f;
|
||||
float angleb = 0.f;
|
||||
|
||||
for (int i = 0; i < NUM_BODY_CONE_SIDES; i ++) {
|
||||
|
||||
// the rectangles that comprise the sides of the cone section are
|
||||
// referenced by "a" and "b" in one dimension, and "1", and "2" in the other dimension.
|
||||
anglea = angleb;
|
||||
angleb = ((float)(i+1) / (float)NUM_BODY_CONE_SIDES) * PIf * 2.0f;
|
||||
angleb = ((float)(i+1) / (float)NUM_BODY_CONE_SIDES) * TWO_PI;
|
||||
|
||||
float sa = sinf(anglea);
|
||||
float sb = sinf(angleb);
|
||||
|
|
|
@ -54,6 +54,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
++avatarIterator;
|
||||
continue;
|
||||
}
|
||||
if (!avatar->isInitialized()) {
|
||||
avatar->init();
|
||||
}
|
||||
if (avatar->getOwningAvatarMixer()) {
|
||||
// this avatar's mixer is still around, go ahead and simulate it
|
||||
avatar->simulate(deltaTime);
|
||||
|
@ -80,7 +83,7 @@ void AvatarManager::renderAvatars(bool forShadowMapOrMirror, bool selfAvatarOnly
|
|||
foreach (const AvatarSharedPointer& avatarPointer, _avatarHash) {
|
||||
Avatar* avatar = static_cast<Avatar*>(avatarPointer.data());
|
||||
if (!avatar->isInitialized()) {
|
||||
avatar->init();
|
||||
continue;
|
||||
}
|
||||
if (avatar == static_cast<Avatar*>(_myAvatar.data())) {
|
||||
_myAvatar->render(forShadowMapOrMirror);
|
||||
|
|
|
@ -56,9 +56,10 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
|
|||
glm::mat3 axes = glm::mat3_cast(_rotation);
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||
state.rotation = glm::angleAxis(-_owningHead->getTweakedRoll(), glm::normalize(inverse * axes[2])) *
|
||||
glm::angleAxis(_owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1])) *
|
||||
glm::angleAxis(-_owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getTweakedRoll(), glm::normalize(inverse * axes[2]))
|
||||
* glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1]))
|
||||
* glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0]))
|
||||
* joint.rotation;
|
||||
}
|
||||
|
||||
void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||
|
@ -69,7 +70,7 @@ void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJ
|
|||
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() +
|
||||
_owningHead->getSaccade() - _translation, 1.0f));
|
||||
glm::quat between = rotationBetween(front, lookAt);
|
||||
const float MAX_ANGLE = 30.0f;
|
||||
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE;
|
||||
state.rotation = glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) *
|
||||
joint.rotation;
|
||||
}
|
||||
|
|
|
@ -183,13 +183,13 @@ void Head::setScale (float scale) {
|
|||
}
|
||||
|
||||
glm::quat Head::getTweakedOrientation() const {
|
||||
return _owningAvatar->getOrientation() * glm::quat(glm::radians(glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() )));
|
||||
return _owningAvatar->getOrientation() * glm::quat(glm::radians(
|
||||
glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() )));
|
||||
}
|
||||
|
||||
glm::quat Head::getCameraOrientation () const {
|
||||
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar);
|
||||
return owningAvatar->getWorldAlignedOrientation()
|
||||
* glm::quat(glm::radians(glm::vec3(_pitch, 0.f, 0.0f)));
|
||||
return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_pitch, 0.f, 0.0f)));
|
||||
}
|
||||
|
||||
glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const {
|
||||
|
|
|
@ -34,15 +34,10 @@
|
|||
using namespace std;
|
||||
|
||||
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
||||
const float YAW_MAG = 500.0f;
|
||||
const float PITCH_MAG = 100.0f;
|
||||
const float YAW_SPEED = 500.0f; // degrees/sec
|
||||
const float PITCH_SPEED = 100.0f; // degrees/sec
|
||||
const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions
|
||||
const float COLLISION_BODY_FORCE = 30.0f; // pertains to avatar-to-avatar collisions
|
||||
const float COLLISION_RADIUS_SCALE = 0.125f;
|
||||
const float MOUSE_RAY_TOUCH_RANGE = 0.01f;
|
||||
const bool USING_HEAD_LEAN = false;
|
||||
const float SKIN_COLOR[] = {1.0f, 0.84f, 0.66f};
|
||||
const float DARK_SKIN_COLOR[] = {0.9f, 0.78f, 0.63f};
|
||||
|
||||
const float DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000;
|
||||
|
||||
|
@ -118,12 +113,13 @@ void MyAvatar::update(float deltaTime) {
|
|||
|
||||
Head* head = getHead();
|
||||
if (OculusManager::isConnected()) {
|
||||
float yaw, pitch, roll;
|
||||
float yaw, pitch, roll; // these angles will be in radians
|
||||
OculusManager::getEulerAngles(yaw, pitch, roll);
|
||||
|
||||
head->setYaw(yaw);
|
||||
head->setPitch(pitch);
|
||||
head->setRoll(roll);
|
||||
// but these euler angles are stored in degrees
|
||||
head->setYaw(yaw * DEGREES_PER_RADIAN);
|
||||
head->setPitch(pitch * DEGREES_PER_RADIAN);
|
||||
head->setRoll(roll * DEGREES_PER_RADIAN);
|
||||
}
|
||||
|
||||
// Get audio loudness data from audio input device
|
||||
|
@ -186,7 +182,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
float radius = getSkeletonHeight() * COLLISION_RADIUS_SCALE;
|
||||
if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) {
|
||||
radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.f));
|
||||
radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cosf(0.5f * RADIANS_PER_DEGREE * myCamera->getFieldOfView()));
|
||||
radius *= COLLISION_RADIUS_SCALAR;
|
||||
}
|
||||
|
||||
|
@ -206,11 +202,11 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
// update body yaw by body yaw delta
|
||||
orientation = orientation * glm::quat(glm::radians(
|
||||
glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime));
|
||||
glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime));
|
||||
// decay body rotation momentum
|
||||
|
||||
const float BODY_SPIN_FRICTION = 7.5f;
|
||||
float bodySpinMomentum = 1.0 - BODY_SPIN_FRICTION * deltaTime;
|
||||
float bodySpinMomentum = 1.f - BODY_SPIN_FRICTION * deltaTime;
|
||||
if (bodySpinMomentum < 0.0f) { bodySpinMomentum = 0.0f; }
|
||||
_bodyPitchDelta *= bodySpinMomentum;
|
||||
_bodyYawDelta *= bodySpinMomentum;
|
||||
|
@ -329,8 +325,6 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
maybeUpdateBillboard();
|
||||
}
|
||||
|
||||
const float MAX_PITCH = 90.0f;
|
||||
|
||||
// Update avatar head rotation with sensor data
|
||||
void MyAvatar::updateFromGyros(float deltaTime) {
|
||||
Faceshift* faceshift = Application::getInstance()->getFaceshift();
|
||||
|
@ -340,12 +334,12 @@ void MyAvatar::updateFromGyros(float deltaTime) {
|
|||
bool trackerActive = false;
|
||||
if (faceshift->isActive()) {
|
||||
estimatedPosition = faceshift->getHeadTranslation();
|
||||
estimatedRotation = safeEulerAngles(faceshift->getHeadRotation());
|
||||
estimatedRotation = glm::degrees(safeEulerAngles(faceshift->getHeadRotation()));
|
||||
trackerActive = true;
|
||||
|
||||
} else if (visage->isActive()) {
|
||||
estimatedPosition = visage->getHeadTranslation();
|
||||
estimatedRotation = safeEulerAngles(visage->getHeadRotation());
|
||||
estimatedRotation = glm::degrees(safeEulerAngles(visage->getHeadRotation()));
|
||||
trackerActive = true;
|
||||
}
|
||||
|
||||
|
@ -492,12 +486,11 @@ void MyAvatar::render(bool forShadowMapOrMirror) {
|
|||
glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z);
|
||||
glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation();
|
||||
glm::vec3 chatAxis = glm::axis(chatRotation);
|
||||
glRotatef(glm::angle(chatRotation), chatAxis.x, chatAxis.y, chatAxis.z);
|
||||
glRotatef(glm::degrees(glm::angle(chatRotation)), chatAxis.x, chatAxis.y, chatAxis.z);
|
||||
|
||||
|
||||
glColor3f(0, 0.8f, 0);
|
||||
glRotatef(180, 0, 1, 0);
|
||||
glRotatef(180, 0, 0, 1);
|
||||
glColor3f(0.f, 0.8f, 0.f);
|
||||
glRotatef(180.f, 0.f, 1.f, 0.f);
|
||||
glRotatef(180.f, 0.f, 0.f, 1.f);
|
||||
glScalef(_scale * CHAT_MESSAGE_SCALE, _scale * CHAT_MESSAGE_SCALE, 1.0f);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
|
@ -513,7 +506,7 @@ void MyAvatar::render(bool forShadowMapOrMirror) {
|
|||
_chatMessage[lastIndex] = '\0';
|
||||
textRenderer()->draw(-width / 2.0f, 0, _chatMessage.c_str());
|
||||
_chatMessage[lastIndex] = lastChar;
|
||||
glColor3f(0, 1, 0);
|
||||
glColor3f(0.f, 1.f, 0.f);
|
||||
textRenderer()->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex);
|
||||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
|
@ -527,7 +520,7 @@ void MyAvatar::renderHeadMouse() const {
|
|||
// TODO? resurrect headMouse stuff?
|
||||
/*
|
||||
// Display small target box at center or head mouse target that can also be used to measure LOD
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
glColor3f(1.f, 1.f, 1.f);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
const int PIXEL_BOX = 16;
|
||||
glBegin(GL_LINES);
|
||||
|
@ -549,7 +542,7 @@ void MyAvatar::renderHeadMouse() const {
|
|||
int eyeTargetX = (_glWidget->width() / 2) - _faceshift.getEstimatedEyeYaw() * EYE_TARGET_PIXELS_PER_DEGREE;
|
||||
int eyeTargetY = (_glWidget->height() / 2) - _faceshift.getEstimatedEyePitch() * EYE_TARGET_PIXELS_PER_DEGREE;
|
||||
|
||||
glColor3f(0.0, 1.0, 1.0);
|
||||
glColor3f(0.f, 1.f, 1.f);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(eyeTargetX - PIXEL_BOX/2, eyeTargetY);
|
||||
|
@ -624,15 +617,15 @@ void MyAvatar::orbit(const glm::vec3& position, int deltaX, int deltaY) {
|
|||
// first orbit horizontally
|
||||
glm::quat orientation = getOrientation();
|
||||
const float ANGULAR_SCALE = 0.5f;
|
||||
glm::quat rotation = glm::angleAxis(deltaX * -ANGULAR_SCALE, orientation * IDENTITY_UP);
|
||||
glm::quat rotation = glm::angleAxis(glm::radians(- deltaX * ANGULAR_SCALE), orientation * IDENTITY_UP);
|
||||
setPosition(position + rotation * (getPosition() - position));
|
||||
orientation = rotation * orientation;
|
||||
setOrientation(orientation);
|
||||
|
||||
// then vertically
|
||||
float oldPitch = getHead()->getPitch();
|
||||
getHead()->setPitch(oldPitch + deltaY * -ANGULAR_SCALE);
|
||||
rotation = glm::angleAxis(getHead()->getPitch() - oldPitch, orientation * IDENTITY_RIGHT);
|
||||
getHead()->setPitch(oldPitch - deltaY * ANGULAR_SCALE);
|
||||
rotation = glm::angleAxis(glm::radians((getHead()->getPitch() - oldPitch)), orientation * IDENTITY_RIGHT);
|
||||
|
||||
setPosition(position + rotation * (getPosition() - position));
|
||||
}
|
||||
|
@ -737,9 +730,9 @@ void MyAvatar::updateThrust(float deltaTime) {
|
|||
_thrust -= _driveKeys[LEFT] * _scale * THRUST_MAG_LATERAL * _thrustMultiplier * deltaTime * right;
|
||||
_thrust += _driveKeys[UP] * _scale * THRUST_MAG_UP * _thrustMultiplier * deltaTime * up;
|
||||
_thrust -= _driveKeys[DOWN] * _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up;
|
||||
_bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_MAG * deltaTime;
|
||||
_bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_MAG * deltaTime;
|
||||
getHead()->setPitch(getHead()->getPitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_MAG * deltaTime);
|
||||
_bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime;
|
||||
_bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_SPEED * deltaTime;
|
||||
getHead()->setPitch(getHead()->getPitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime);
|
||||
|
||||
// If thrust keys are being held down, slowly increase thrust to allow reaching great speeds
|
||||
if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) {
|
||||
|
@ -1037,7 +1030,7 @@ void MyAvatar::updateChatCircle(float deltaTime) {
|
|||
const float CIRCLE_INFLUENCE_SCALE = 2.0f;
|
||||
const float MIN_RADIUS = 0.3f;
|
||||
for (int i = sortedAvatars.size() - 1; i >= 0; i--) {
|
||||
float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / PI_TIMES_TWO);
|
||||
float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / TWO_PI);
|
||||
if (glm::distance(_position, sortedAvatars[i].accumulatedCenter) > radius * CIRCLE_INFLUENCE_SCALE) {
|
||||
sortedAvatars.remove(i);
|
||||
} else {
|
||||
|
@ -1048,7 +1041,7 @@ void MyAvatar::updateChatCircle(float deltaTime) {
|
|||
return;
|
||||
}
|
||||
center = sortedAvatars.last().accumulatedCenter;
|
||||
float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / PI_TIMES_TWO);
|
||||
float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / TWO_PI);
|
||||
|
||||
// compute the average up vector
|
||||
glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP;
|
||||
|
@ -1069,18 +1062,18 @@ void MyAvatar::updateChatCircle(float deltaTime) {
|
|||
glm::vec3 delta = _position - center;
|
||||
glm::vec3 projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f);
|
||||
float myAngle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f;
|
||||
float leftDistance = PI_TIMES_TWO;
|
||||
float rightDistance = PI_TIMES_TWO;
|
||||
float leftDistance = TWO_PI;
|
||||
float rightDistance = TWO_PI;
|
||||
foreach (const SortedAvatar& sortedAvatar, sortedAvatars) {
|
||||
delta = sortedAvatar.avatar->getPosition() - center;
|
||||
projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f);
|
||||
float angle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f;
|
||||
if (angle < myAngle) {
|
||||
leftDistance = min(myAngle - angle, leftDistance);
|
||||
rightDistance = min(PI_TIMES_TWO - (myAngle - angle), rightDistance);
|
||||
rightDistance = min(TWO_PI - (myAngle - angle), rightDistance);
|
||||
|
||||
} else {
|
||||
leftDistance = min(PI_TIMES_TWO - (angle - myAngle), leftDistance);
|
||||
leftDistance = min(TWO_PI - (angle - myAngle), leftDistance);
|
||||
rightDistance = min(angle - myAngle, rightDistance);
|
||||
}
|
||||
}
|
||||
|
@ -1126,13 +1119,6 @@ void MyAvatar::setGravity(glm::vec3 gravity) {
|
|||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setOrientation(const glm::quat& orientation) {
|
||||
glm::vec3 eulerAngles = safeEulerAngles(orientation);
|
||||
_bodyPitch = eulerAngles.x;
|
||||
_bodyYaw = eulerAngles.y;
|
||||
_bodyRoll = eulerAngles.z;
|
||||
}
|
||||
|
||||
void MyAvatar::goHome() {
|
||||
qDebug("Going Home!");
|
||||
setPosition(START_LOCATION);
|
||||
|
@ -1169,7 +1155,7 @@ void MyAvatar::updateLocationInDataServer() {
|
|||
|
||||
if (accountManager.isLoggedIn()) {
|
||||
QString positionString(createByteArray(_position));
|
||||
QString orientationString(createByteArray(safeEulerAngles(getOrientation())));
|
||||
QString orientationString(createByteArray(glm::degrees(safeEulerAngles(getOrientation()))));
|
||||
|
||||
// construct the json to put the user's location
|
||||
QString locationPutJson = QString() + "{\"address\":{\"position\":\""
|
||||
|
@ -1202,10 +1188,10 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
|
|||
NodeList::getInstance()->getDomainInfo().setHostname(domainHostnameString);
|
||||
|
||||
// orient the user to face the target
|
||||
glm::quat newOrientation = glm::quat(glm::radians(glm::vec3(orientationItems[0].toFloat(),
|
||||
orientationItems[1].toFloat(),
|
||||
orientationItems[2].toFloat())))
|
||||
* glm::angleAxis(180.0f, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
glm::quat newOrientation = glm::quat(glm::vec3(orientationItems[0].toFloat(),
|
||||
orientationItems[1].toFloat(),
|
||||
orientationItems[2].toFloat()))
|
||||
* glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
setOrientation(newOrientation);
|
||||
|
||||
// move the user a couple units away
|
||||
|
|
|
@ -44,10 +44,8 @@ public:
|
|||
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
|
||||
void setLeanScale(float scale) { _leanScale = scale; }
|
||||
void setGravity(glm::vec3 gravity);
|
||||
void setOrientation(const glm::quat& orientation);
|
||||
void setMoveTarget(const glm::vec3 moveTarget);
|
||||
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; }
|
||||
|
||||
|
||||
// getters
|
||||
float getSpeed() const { return _speed; }
|
||||
|
@ -55,7 +53,7 @@ public:
|
|||
float getLeanScale() const { return _leanScale; }
|
||||
float getElapsedTimeStopped() const { return _elapsedTimeStopped; }
|
||||
float getElapsedTimeMoving() const { return _elapsedTimeMoving; }
|
||||
float getAbsoluteHeadYaw() const;
|
||||
float getAbsoluteHeadYaw() const; // degrees
|
||||
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
||||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||
glm::vec3 getGravity() const { return _gravity; }
|
||||
|
@ -68,7 +66,7 @@ public:
|
|||
|
||||
// Set what driving keys are being pressed to control thrust levels
|
||||
void setDriveKeys(int key, float val) { _driveKeys[key] = val; };
|
||||
bool getDriveKeys(int key) { return _driveKeys[key]; };
|
||||
bool getDriveKeys(int key) { return _driveKeys[key] != 0.f; };
|
||||
void jump() { _shouldJump = true; };
|
||||
|
||||
bool isMyAvatar() { return true; }
|
||||
|
@ -101,8 +99,8 @@ public slots:
|
|||
|
||||
private:
|
||||
bool _mousePressed;
|
||||
float _bodyPitchDelta;
|
||||
float _bodyRollDelta;
|
||||
float _bodyPitchDelta; // degrees
|
||||
float _bodyRollDelta; // degrees
|
||||
bool _shouldJump;
|
||||
float _driveKeys[MAX_DRIVE_KEYS];
|
||||
glm::vec3 _gravity;
|
||||
|
|
|
@ -19,18 +19,14 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) :
|
|||
}
|
||||
|
||||
void SkeletonModel::simulate(float deltaTime, bool delayLoad) {
|
||||
if (!isActive()) {
|
||||
Model::simulate(deltaTime, delayLoad);
|
||||
return;
|
||||
}
|
||||
setTranslation(_owningAvatar->getPosition());
|
||||
setRotation(_owningAvatar->getOrientation() * glm::angleAxis(180.0f, glm::vec3(0.0f, 1.0f, 0.0f)));
|
||||
setRotation(_owningAvatar->getOrientation() * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)));
|
||||
const float MODEL_SCALE = 0.0006f;
|
||||
setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale() * MODEL_SCALE);
|
||||
|
||||
|
||||
Model::simulate(deltaTime, delayLoad);
|
||||
|
||||
if (!_owningAvatar->isMyAvatar()) {
|
||||
|
||||
if (!(isActive() && _owningAvatar->isMyAvatar())) {
|
||||
return; // only simulate for own avatar
|
||||
}
|
||||
|
||||
|
@ -150,7 +146,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
|
|||
|
||||
// rotate palm according to average finger direction
|
||||
float directionLength = glm::length(direction);
|
||||
const int MIN_ROTATION_FINGERS = 3;
|
||||
const unsigned int MIN_ROTATION_FINGERS = 3;
|
||||
if (directionLength > EPSILON && palm.getNumFingers() >= MIN_ROTATION_FINGERS) {
|
||||
applyRotationDelta(jointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction), false);
|
||||
getJointRotation(jointIndex, palmRotation, true);
|
||||
|
@ -199,8 +195,9 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const
|
|||
glm::mat3 axes = glm::mat3_cast(_rotation);
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)));
|
||||
state.rotation = glm::angleAxis(-_owningAvatar->getHead()->getLeanSideways(), glm::normalize(inverse * axes[2])) *
|
||||
glm::angleAxis(-_owningAvatar->getHead()->getLeanForward(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getLeanSideways(),
|
||||
glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getLeanForward(),
|
||||
glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
}
|
||||
|
||||
void SkeletonModel::stretchArm(int jointIndex, const glm::vec3& position) {
|
||||
|
|
|
@ -65,8 +65,8 @@ void Faceshift::update() {
|
|||
return;
|
||||
}
|
||||
// get the euler angles relative to the window
|
||||
glm::vec3 eulers = safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3(
|
||||
(_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f))));
|
||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3(
|
||||
(_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f)))));
|
||||
|
||||
// compute and subtract the long term average
|
||||
const float LONG_TERM_AVERAGE_SMOOTHING = 0.999f;
|
||||
|
|
|
@ -33,6 +33,7 @@ public:
|
|||
const glm::vec3& getHeadAngularVelocity() const { return _headAngularVelocity; }
|
||||
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
||||
|
||||
// these pitch/yaw angles are in degrees
|
||||
float getEyeGazeLeftPitch() const { return _eyeGazeLeftPitch; }
|
||||
float getEyeGazeLeftYaw() const { return _eyeGazeLeftYaw; }
|
||||
|
||||
|
@ -96,9 +97,9 @@ private:
|
|||
glm::vec3 _headAngularVelocity;
|
||||
glm::vec3 _headTranslation;
|
||||
|
||||
// degrees
|
||||
float _eyeGazeLeftPitch;
|
||||
float _eyeGazeLeftYaw;
|
||||
|
||||
float _eyeGazeRightPitch;
|
||||
float _eyeGazeRightYaw;
|
||||
|
||||
|
@ -121,10 +122,12 @@ private:
|
|||
|
||||
int _jawOpenIndex;
|
||||
|
||||
// degrees
|
||||
float _longTermAverageEyePitch;
|
||||
float _longTermAverageEyeYaw;
|
||||
bool _longTermAverageInitialized;
|
||||
|
||||
// degrees
|
||||
float _estimatedEyePitch;
|
||||
float _estimatedEyeYaw;
|
||||
};
|
||||
|
|
|
@ -27,7 +27,7 @@ int OculusManager::_scaleLocation;
|
|||
int OculusManager::_scaleInLocation;
|
||||
int OculusManager::_hmdWarpParamLocation;
|
||||
bool OculusManager::_isConnected = false;
|
||||
float OculusManager::_yawOffset = 0;
|
||||
float OculusManager::_yawOffset = 0.0f; // radians
|
||||
|
||||
#ifdef HAVE_LIBOVR
|
||||
using namespace OVR;
|
||||
|
@ -198,12 +198,7 @@ void OculusManager::updateYawOffset() {
|
|||
void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
|
||||
#ifdef HAVE_LIBOVR
|
||||
_sensorFusion->GetOrientation().GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
|
||||
|
||||
// convert each angle to degrees
|
||||
// remove the yaw offset from the returned yaw
|
||||
yaw = glm::degrees(yaw - _yawOffset);
|
||||
pitch = glm::degrees(pitch);
|
||||
roll = glm::degrees(roll);
|
||||
yaw = yaw - _yawOffset;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,9 @@ public:
|
|||
|
||||
static void reset();
|
||||
|
||||
/// param \yaw[out] yaw in radians
|
||||
/// param \pitch[out] pitch in radians
|
||||
/// param \roll[out] roll in radians
|
||||
static void getEulerAngles(float& yaw, float& pitch, float& roll);
|
||||
|
||||
static void updateYawOffset();
|
||||
|
|
|
@ -60,7 +60,7 @@ void SixenseManager::update(float deltaTime) {
|
|||
// Either find a palm matching the sixense controller, or make a new one
|
||||
PalmData* palm;
|
||||
bool foundHand = false;
|
||||
for (int j = 0; j < hand->getNumPalms(); j++) {
|
||||
for (size_t j = 0; j < hand->getNumPalms(); j++) {
|
||||
if (hand->getPalms()[j].getSixenseID() == data.controller_index) {
|
||||
palm = &(hand->getPalms()[j]);
|
||||
foundHand = true;
|
||||
|
@ -89,7 +89,7 @@ void SixenseManager::update(float deltaTime) {
|
|||
|
||||
// Rotation of Palm
|
||||
glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]);
|
||||
rotation = glm::angleAxis(180.0f, glm::vec3(0.f, 1.f, 0.f)) * rotation;
|
||||
rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * rotation;
|
||||
const glm::vec3 PALM_VECTOR(0.0f, -1.0f, 0.0f);
|
||||
glm::vec3 newNormal = rotation * PALM_VECTOR;
|
||||
palm->setRawNormal(newNormal);
|
||||
|
@ -128,7 +128,7 @@ void SixenseManager::update(float deltaTime) {
|
|||
}
|
||||
|
||||
// if the controllers haven't been moved in a while, disable
|
||||
const int MOVEMENT_DISABLE_DURATION = 30 * 1000 * 1000;
|
||||
const unsigned int MOVEMENT_DISABLE_DURATION = 30 * 1000 * 1000;
|
||||
if (usecTimestampNow() - _lastMovement > MOVEMENT_DISABLE_DURATION) {
|
||||
for (vector<PalmData>::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) {
|
||||
it->setActive(false);
|
||||
|
|
|
@ -52,7 +52,7 @@ void TV3DManager::setFrustum(Camera& whichCamera) {
|
|||
double nearZ = whichCamera.getNearClip(); // near clipping plane
|
||||
double screenZ = Application::getInstance()->getViewFrustum()->getFocalLength(); // screen projection plane
|
||||
|
||||
double top = nearZ * tan(DTR * fovy / 2); //sets top of frustum based on fovy and near clipping plane
|
||||
double top = nearZ * tan(DTR * fovy / 2.0); //sets top of frustum based on fovy and near clipping plane
|
||||
double right = _aspect * top; // sets right of frustum based on aspect ratio
|
||||
double frustumshift = (IOD / 2) * nearZ / screenZ;
|
||||
|
||||
|
@ -136,4 +136,4 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
|
||||
// reset the viewport to how we started
|
||||
glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,13 +10,15 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Visage.h"
|
||||
#include "renderer/FBXReader.h"
|
||||
|
||||
// this has to go after our normal includes, because its definition of HANDLE conflicts with Qt's
|
||||
#ifdef HAVE_VISAGE
|
||||
#include <VisageTracker2.h>
|
||||
#endif
|
||||
|
||||
#include "Visage.h"
|
||||
#include "renderer/FBXReader.h"
|
||||
|
||||
namespace VisageSDK {
|
||||
#ifdef WIN32
|
||||
void __declspec(dllimport) initializeLicenseManager(char* licenseKeyFileName);
|
||||
|
@ -36,9 +38,9 @@ Visage::Visage() :
|
|||
_estimatedEyeYaw(0.0f) {
|
||||
|
||||
#ifdef HAVE_VISAGE
|
||||
QByteArray licensePath = Application::resourcesPath() + "visage/license.vlc";
|
||||
QByteArray licensePath = Application::resourcesPath().toLatin1() + "visage/license.vlc";
|
||||
initializeLicenseManager(licensePath.data());
|
||||
_tracker = new VisageTracker2(Application::resourcesPath() + "visage/Facial Features Tracker - Asymmetric.cfg");
|
||||
_tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg");
|
||||
if (_tracker->trackFromCam()) {
|
||||
_data = new FaceData();
|
||||
|
||||
|
@ -65,29 +67,25 @@ static int rightEyeBlinkIndex = 1;
|
|||
|
||||
static QMultiHash<QByteArray, QPair<int, float> > createActionUnitNameMap() {
|
||||
QMultiHash<QByteArray, QPair<QByteArray, float> > blendshapeMap;
|
||||
blendshapeMap.insert("Sneer", QPair<QByteArray, float>("au_nose_wrinkler", 1.0f));
|
||||
blendshapeMap.insert("JawFwd", QPair<QByteArray, float>("au_jaw_z_push", 1.0f));
|
||||
blendshapeMap.insert("JawLeft", QPair<QByteArray, float>("au_jaw_x_push", 1.0f));
|
||||
blendshapeMap.insert("JawOpen", QPair<QByteArray, float>("au_jaw_drop", 1.0f));
|
||||
blendshapeMap.insert("LipsLowerDown", QPair<QByteArray, float>("au_lower_lip_drop", 1.0f));
|
||||
blendshapeMap.insert("LipsUpperUp", QPair<QByteArray, float>("au_upper_lip_raiser", 1.0f));
|
||||
blendshapeMap.insert("LipsStretch_R", QPair<QByteArray, float>("au_lip_stretcher_left", 1.0f));
|
||||
blendshapeMap.insert("LipsUpperOpen", QPair<QByteArray, float>("au_upper_lip_raiser", 1.0f));
|
||||
blendshapeMap.insert("LipsStretch_R", QPair<QByteArray, float>("au_lip_stretcher_left", 0.5f));
|
||||
blendshapeMap.insert("MouthSmile_L", QPair<QByteArray, float>("au_lip_corner_depressor", -1.0f));
|
||||
blendshapeMap.insert("MouthSmile_R", QPair<QByteArray, float>("au_lip_corner_depressor", -1.0f));
|
||||
blendshapeMap.insert("LipsPucker", QPair<QByteArray, float>("au_lip_presser", 0.0f));
|
||||
blendshapeMap.insert("BrowsU_R", QPair<QByteArray, float>("au_left_outer_brow_raiser", 1.0f));
|
||||
blendshapeMap.insert("BrowsU_C", QPair<QByteArray, float>("au_left_inner_brow_raiser", 0.5f));
|
||||
blendshapeMap.insert("BrowsU_C", QPair<QByteArray, float>("au_left_inner_brow_raiser", 1.0f));
|
||||
blendshapeMap.insert("BrowsD_R", QPair<QByteArray, float>("au_left_brow_lowerer", 1.0f));
|
||||
blendshapeMap.insert("EyeBlink_L", QPair<QByteArray, float>("au_leye_closed", 1.0f));
|
||||
blendshapeMap.insert("EyeBlink_R", QPair<QByteArray, float>("au_leye_closed", 1.0f));
|
||||
blendshapeMap.insert("EyeSquint_L", QPair<QByteArray, float>("au_lid_tightener", 1.0f));
|
||||
blendshapeMap.insert("EyeSquint_R", QPair<QByteArray, float>("au_lid_tightener", 1.0f));
|
||||
blendshapeMap.insert("EyeBlink_R", QPair<QByteArray, float>("au_reye_closed", 1.0f));
|
||||
blendshapeMap.insert("EyeOpen_L", QPair<QByteArray, float>("au_upper_lid_raiser", 1.0f));
|
||||
blendshapeMap.insert("EyeOpen_R", QPair<QByteArray, float>("au_upper_lid_raiser", 1.0f));
|
||||
blendshapeMap.insert("MouthLeft", QPair<QByteArray, float>("au_lower_lip_x_push", 0.0f));
|
||||
blendshapeMap.insert("LipsStretch_L", QPair<QByteArray, float>("au_lip_stretcher_right", 1.0f));
|
||||
blendshapeMap.insert("LipLowerOpen", QPair<QByteArray, float>("au_lower_lip_x_push", 1.0f));
|
||||
blendshapeMap.insert("LipsStretch_L", QPair<QByteArray, float>("au_lip_stretcher_right", 0.5f));
|
||||
blendshapeMap.insert("BrowsU_L", QPair<QByteArray, float>("au_right_outer_brow_raiser", 1.0f));
|
||||
blendshapeMap.insert("BrowsU_C", QPair<QByteArray, float>("au_right_inner_brow_raiser", 0.5f));
|
||||
blendshapeMap.insert("BrowsU_C", QPair<QByteArray, float>("au_right_inner_brow_raiser", 1.0f));
|
||||
blendshapeMap.insert("BrowsD_L", QPair<QByteArray, float>("au_right_brow_lowerer", 1.0f));
|
||||
|
||||
QMultiHash<QByteArray, QPair<int, float> > actionUnitNameMap;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QTranslator>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
|
@ -40,6 +41,10 @@ int main(int argc, const char * argv[]) {
|
|||
{
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
Application app(argc, const_cast<char**>(argv), startup_time);
|
||||
|
||||
QTranslator translator;
|
||||
translator.load("interface_en");
|
||||
app.installTranslator(&translator);
|
||||
|
||||
qDebug( "Created QT Application.");
|
||||
exitCode = app.exec();
|
||||
|
|
|
@ -66,7 +66,7 @@ template<class T> QVariant readBinaryArray(QDataStream& in) {
|
|||
in >> compressedLength;
|
||||
|
||||
QVector<T> values;
|
||||
const int DEFLATE_ENCODING = 1;
|
||||
const unsigned int DEFLATE_ENCODING = 1;
|
||||
if (encoding == DEFLATE_ENCODING) {
|
||||
// preface encoded data with uncompressed length
|
||||
QByteArray compressed(sizeof(quint32) + compressedLength, 0);
|
||||
|
@ -163,7 +163,7 @@ FBXNode parseBinaryFBXNode(QDataStream& in) {
|
|||
in >> nameLength;
|
||||
|
||||
FBXNode node;
|
||||
const int MIN_VALID_OFFSET = 40;
|
||||
const unsigned int MIN_VALID_OFFSET = 40;
|
||||
if (endOffset < MIN_VALID_OFFSET || nameLength == 0) {
|
||||
// use a null name to indicate a null node
|
||||
return node;
|
||||
|
@ -533,8 +533,8 @@ public:
|
|||
glm::quat postRotation;
|
||||
glm::mat4 postTransform;
|
||||
|
||||
glm::vec3 rotationMin;
|
||||
glm::vec3 rotationMax;
|
||||
glm::vec3 rotationMin; // radians
|
||||
glm::vec3 rotationMax; // radians
|
||||
};
|
||||
|
||||
glm::mat4 getGlobalTransform(const QMultiHash<QString, QString>& parentMap,
|
||||
|
@ -806,7 +806,7 @@ void setTangents(FBXMesh& mesh, int firstIndex, int secondIndex) {
|
|||
}
|
||||
glm::vec2 texCoordDelta = mesh.texCoords.at(secondIndex) - mesh.texCoords.at(firstIndex);
|
||||
mesh.tangents[firstIndex] += glm::cross(glm::angleAxis(
|
||||
-glm::degrees(atan2f(-texCoordDelta.t, texCoordDelta.s)), normal) * glm::normalize(bitangent), normal);
|
||||
- atan2f(-texCoordDelta.t, texCoordDelta.s), normal) * glm::normalize(bitangent), normal);
|
||||
}
|
||||
|
||||
QVector<int> getIndices(const QVector<QString> ids, QVector<QString> modelIDs) {
|
||||
|
@ -1000,6 +1000,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
jointRightFingertipIDs[index] = getID(object.properties);
|
||||
}
|
||||
glm::vec3 translation;
|
||||
// NOTE: the euler angles as supplied by the FBX file are in degrees
|
||||
glm::vec3 rotationOffset;
|
||||
glm::vec3 preRotation, rotation, postRotation;
|
||||
glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||
|
@ -1054,7 +1055,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
} else if (property.properties.at(0) == "RotationMin") {
|
||||
rotationMin = getVec3(property.properties, index);
|
||||
|
||||
} else if (property.properties.at(0) == "RotationMax") {
|
||||
}
|
||||
// NOTE: these rotation limits are stored in degrees (NOT radians)
|
||||
else if (property.properties.at(0) == "RotationMax") {
|
||||
rotationMax = getVec3(property.properties, index);
|
||||
|
||||
} else if (property.properties.at(0) == "RotationMinX") {
|
||||
|
@ -1104,10 +1107,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
model.postRotation = glm::quat(glm::radians(postRotation));
|
||||
model.postTransform = glm::translate(-rotationPivot) * glm::translate(scalePivot) *
|
||||
glm::scale(scale) * glm::translate(-scalePivot);
|
||||
model.rotationMin = glm::vec3(rotationMinX ? rotationMin.x : -180.0f,
|
||||
rotationMinY ? rotationMin.y : -180.0f, rotationMinZ ? rotationMin.z : -180.0f);
|
||||
model.rotationMax = glm::vec3(rotationMaxX ? rotationMax.x : 180.0f,
|
||||
rotationMaxY ? rotationMax.y : 180.0f, rotationMaxZ ? rotationMax.z : 180.0f);
|
||||
// NOTE: anbgles from the FBX file are in degrees
|
||||
// so we convert them to radians for the FBXModel class
|
||||
model.rotationMin = glm::radians(glm::vec3(rotationMinX ? rotationMin.x : -180.0f,
|
||||
rotationMinY ? rotationMin.y : -180.0f, rotationMinZ ? rotationMin.z : -180.0f));
|
||||
model.rotationMax = glm::radians(glm::vec3(rotationMaxX ? rotationMax.x : 180.0f,
|
||||
rotationMaxY ? rotationMax.y : 180.0f, rotationMaxZ ? rotationMax.z : 180.0f));
|
||||
models.insert(getID(object.properties), model);
|
||||
|
||||
} else if (object.name == "Texture") {
|
||||
|
@ -1324,6 +1329,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
|
||||
geometry.bindExtents.reset();
|
||||
geometry.staticExtents.reset();
|
||||
geometry.meshExtents.reset();
|
||||
|
||||
QVariantHash springs = mapping.value("spring").toHash();
|
||||
QVariant defaultSpring = springs.value("default");
|
||||
|
@ -1335,6 +1341,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
extracted.mesh.springiness = springs.value(models.value(modelID).name, defaultSpring).toFloat();
|
||||
glm::mat4 modelTransform = getGlobalTransform(parentMap, models, modelID);
|
||||
|
||||
// compute the mesh extents from the transformed vertices
|
||||
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
||||
glm::vec3 transformedVertex = glm::vec3(modelTransform * glm::vec4(vertex, 1.0f));
|
||||
geometry.meshExtents.minimum = glm::min(geometry.meshExtents.minimum, transformedVertex);
|
||||
geometry.meshExtents.maximum = glm::max(geometry.meshExtents.maximum, transformedVertex);
|
||||
}
|
||||
|
||||
// look for textures, material properties
|
||||
int materialIndex = 0;
|
||||
int textureIndex = 0;
|
||||
|
@ -1812,5 +1825,7 @@ FBXGeometry readSVO(const QByteArray& model) {
|
|||
|
||||
geometry.meshes.append(mesh);
|
||||
|
||||
geometry.meshExtents.maximum = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
|
|
@ -76,8 +76,8 @@ public:
|
|||
glm::quat postRotation;
|
||||
glm::mat4 postTransform;
|
||||
glm::mat4 transform;
|
||||
glm::vec3 rotationMin;
|
||||
glm::vec3 rotationMax;
|
||||
glm::vec3 rotationMin; // radians
|
||||
glm::vec3 rotationMax; // radians
|
||||
glm::quat inverseDefaultRotation;
|
||||
glm::quat inverseBindRotation;
|
||||
glm::mat4 bindTransform;
|
||||
|
@ -179,6 +179,7 @@ public:
|
|||
|
||||
Extents bindExtents;
|
||||
Extents staticExtents;
|
||||
Extents meshExtents;
|
||||
|
||||
QVector<FBXAttachment> attachments;
|
||||
|
||||
|
|
|
@ -30,11 +30,11 @@ void GeometryCache::renderHemisphere(int slices, int stacks) {
|
|||
GLfloat* vertexData = new GLfloat[vertices * 3];
|
||||
GLfloat* vertex = vertexData;
|
||||
for (int i = 0; i < stacks - 1; i++) {
|
||||
float phi = PIf * 0.5f * i / (stacks - 1);
|
||||
float phi = PI_OVER_TWO * float(i) / float(stacks - 1);
|
||||
float z = sinf(phi), radius = cosf(phi);
|
||||
|
||||
for (int j = 0; j < slices; j++) {
|
||||
float theta = PIf * 2.0f * j / slices;
|
||||
float theta = TWO_PI * float(j) / float(slices);
|
||||
|
||||
*(vertex++) = sinf(theta) * radius;
|
||||
*(vertex++) = cosf(theta) * radius;
|
||||
|
@ -180,7 +180,7 @@ void GeometryCache::renderHalfCylinder(int slices, int stacks) {
|
|||
float y = (float)i / (stacks - 1);
|
||||
|
||||
for (int j = 0; j <= slices; j++) {
|
||||
float theta = 3 * PIf / 2 + PIf * j / slices;
|
||||
float theta = 3.f * PI_OVER_TWO + PI * float(j) / float(slices);
|
||||
|
||||
//normals
|
||||
*(vertex++) = sinf(theta);
|
||||
|
@ -294,7 +294,8 @@ QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, cons
|
|||
QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url,
|
||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
||||
|
||||
QSharedPointer<NetworkGeometry> geometry(new NetworkGeometry(url, fallback.staticCast<NetworkGeometry>(), delayLoad));
|
||||
QSharedPointer<NetworkGeometry> geometry(new NetworkGeometry(url, fallback.staticCast<NetworkGeometry>(), delayLoad),
|
||||
&Resource::allReferencesCleared);
|
||||
geometry->setLODParent(geometry);
|
||||
return geometry.staticCast<Resource>();
|
||||
}
|
||||
|
@ -377,30 +378,6 @@ QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance
|
|||
return lod;
|
||||
}
|
||||
|
||||
glm::vec4 NetworkGeometry::computeAverageColor() const {
|
||||
glm::vec4 totalColor;
|
||||
int totalTriangles = 0;
|
||||
for (int i = 0; i < _meshes.size(); i++) {
|
||||
const FBXMesh& mesh = _geometry.meshes.at(i);
|
||||
if (mesh.isEye) {
|
||||
continue; // skip eyes
|
||||
}
|
||||
const NetworkMesh& networkMesh = _meshes.at(i);
|
||||
for (int j = 0; j < mesh.parts.size(); j++) {
|
||||
const FBXMeshPart& part = mesh.parts.at(j);
|
||||
const NetworkMeshPart& networkPart = networkMesh.parts.at(j);
|
||||
glm::vec4 color = glm::vec4(part.diffuseColor, 1.0f);
|
||||
if (networkPart.diffuseTexture) {
|
||||
color *= networkPart.diffuseTexture->getAverageColor();
|
||||
}
|
||||
int triangles = part.quadIndices.size() * 2 + part.triangleIndices.size();
|
||||
totalColor += color * (float) triangles;
|
||||
totalTriangles += triangles;
|
||||
}
|
||||
}
|
||||
return (totalTriangles == 0) ? glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) : totalColor / (float) totalTriangles;
|
||||
}
|
||||
|
||||
void NetworkGeometry::setLoadPriority(const QPointer<QObject>& owner, float priority) {
|
||||
Resource::setLoadPriority(owner, priority);
|
||||
|
||||
|
@ -536,6 +513,15 @@ void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
|
|||
QThreadPool::globalInstance()->start(new GeometryReader(_self, url, reply, _mapping));
|
||||
}
|
||||
|
||||
void NetworkGeometry::reinsert() {
|
||||
Resource::reinsert();
|
||||
|
||||
_lodParent = qWeakPointerCast<NetworkGeometry, Resource>(_self);
|
||||
foreach (const QSharedPointer<NetworkGeometry>& lod, _lods) {
|
||||
lod->setLODParent(_lodParent);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
|
||||
_geometry = geometry;
|
||||
|
||||
|
|
|
@ -79,9 +79,6 @@ public:
|
|||
const FBXGeometry& getFBXGeometry() const { return _geometry; }
|
||||
const QVector<NetworkMesh>& getMeshes() const { return _meshes; }
|
||||
|
||||
/// Returns the average color of all meshes in the geometry.
|
||||
glm::vec4 computeAverageColor() const;
|
||||
|
||||
virtual void setLoadPriority(const QPointer<QObject>& owner, float priority);
|
||||
virtual void setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities);
|
||||
virtual void clearLoadPriority(const QPointer<QObject>& owner);
|
||||
|
@ -89,6 +86,7 @@ public:
|
|||
protected:
|
||||
|
||||
virtual void downloadFinished(QNetworkReply* reply);
|
||||
virtual void reinsert();
|
||||
|
||||
Q_INVOKABLE void setGeometry(const FBXGeometry& geometry);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ using namespace std;
|
|||
|
||||
Model::Model(QObject* parent) :
|
||||
QObject(parent),
|
||||
_scale(1.0f, 1.0f, 1.0f),
|
||||
_shapesAreDirty(true),
|
||||
_lodDistance(0.0f),
|
||||
_pupilDilation(0.0f) {
|
||||
|
@ -327,6 +328,8 @@ bool Model::render(float alpha) {
|
|||
|
||||
glDisable(GL_COLOR_MATERIAL);
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
// render opaque meshes with alpha testing
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
|
@ -338,8 +341,6 @@ bool Model::render(float alpha) {
|
|||
|
||||
// render translucent meshes afterwards, with back face culling
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
renderMeshes(alpha, true);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
@ -496,10 +497,6 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo
|
|||
}
|
||||
}
|
||||
|
||||
glm::vec4 Model::computeAverageColor() const {
|
||||
return _geometry ? _geometry->computeAverageColor() : glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
bool Model::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
|
||||
const glm::vec3 relativeOrigin = origin - _translation;
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
|
@ -759,15 +756,15 @@ float Model::getLimbLength(int jointIndex) const {
|
|||
void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain) {
|
||||
JointState& state = _jointStates[jointIndex];
|
||||
const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex];
|
||||
if (!constrain || (joint.rotationMin == glm::vec3(-180.0f, -180.0f, -180.0f) &&
|
||||
joint.rotationMax == glm::vec3(180.0f, 180.0f, 180.0f))) {
|
||||
if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) &&
|
||||
joint.rotationMax == glm::vec3(PI, PI, PI))) {
|
||||
// no constraints
|
||||
state.rotation = state.rotation * glm::inverse(state.combinedRotation) * delta * state.combinedRotation;
|
||||
state.combinedRotation = delta * state.combinedRotation;
|
||||
return;
|
||||
}
|
||||
glm::quat newRotation = glm::quat(glm::radians(glm::clamp(safeEulerAngles(state.rotation *
|
||||
glm::inverse(state.combinedRotation) * delta * state.combinedRotation), joint.rotationMin, joint.rotationMax)));
|
||||
glm::quat newRotation = glm::quat(glm::clamp(safeEulerAngles(state.rotation *
|
||||
glm::inverse(state.combinedRotation) * delta * state.combinedRotation), joint.rotationMin, joint.rotationMax));
|
||||
state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation;
|
||||
state.rotation = newRotation;
|
||||
}
|
||||
|
@ -788,7 +785,7 @@ void Model::renderCollisionProxies(float alpha) {
|
|||
glTranslatef(position.x, position.y, position.z);
|
||||
const glm::quat& rotation = shape->getRotation();
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
// draw a grey sphere at shape position
|
||||
glColor4f(0.75f, 0.75f, 0.75f, alpha);
|
||||
|
@ -863,7 +860,7 @@ void Model::applyCollision(CollisionInfo& collision) {
|
|||
axis = glm::normalize(axis);
|
||||
glm::vec3 end;
|
||||
getJointPosition(jointIndex, end);
|
||||
glm::vec3 newEnd = start + glm::angleAxis(glm::degrees(angle), axis) * (end - start);
|
||||
glm::vec3 newEnd = start + glm::angleAxis(angle, axis) * (end - start);
|
||||
// try to move it
|
||||
setJointPosition(jointIndex, newEnd, -1, true);
|
||||
}
|
||||
|
|
|
@ -175,9 +175,6 @@ public:
|
|||
/// Returns the extended length from the right hand to its first free ancestor.
|
||||
float getRightArmLength() const;
|
||||
|
||||
/// Returns the average color of all meshes in the geometry.
|
||||
glm::vec4 computeAverageColor() const;
|
||||
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
|
||||
/// \param shapes list of pointers shapes to test against Model
|
||||
|
|
|
@ -113,8 +113,7 @@ GLuint TextureCache::getFileTextureID(const QString& filename) {
|
|||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
_fileTextureIDs.insert(filename, id);
|
||||
|
@ -128,9 +127,12 @@ QSharedPointer<NetworkTexture> TextureCache::getTexture(const QUrl& url, bool no
|
|||
}
|
||||
QSharedPointer<NetworkTexture> texture = _dilatableNetworkTextures.value(url);
|
||||
if (texture.isNull()) {
|
||||
texture = QSharedPointer<NetworkTexture>(new DilatableNetworkTexture(url));
|
||||
texture = QSharedPointer<NetworkTexture>(new DilatableNetworkTexture(url), &Resource::allReferencesCleared);
|
||||
texture->setSelf(texture);
|
||||
texture->setCache(this);
|
||||
_dilatableNetworkTextures.insert(url, texture);
|
||||
} else {
|
||||
_unusedResources.remove(texture->getLRUKey());
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
@ -229,7 +231,7 @@ bool TextureCache::eventFilter(QObject* watched, QEvent* event) {
|
|||
|
||||
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
|
||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
||||
return QSharedPointer<Resource>(new NetworkTexture(url, *(const bool*)extra));
|
||||
return QSharedPointer<Resource>(new NetworkTexture(url, *(const bool*)extra), &Resource::allReferencesCleared);
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* TextureCache::createFramebufferObject() {
|
||||
|
@ -254,7 +256,6 @@ Texture::~Texture() {
|
|||
|
||||
NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) :
|
||||
Resource(url),
|
||||
_averageColor(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
_translucent(false) {
|
||||
|
||||
if (!url.isValid()) {
|
||||
|
@ -297,27 +298,20 @@ void ImageReader::run() {
|
|||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
// sum up the colors for the average and check for translucency
|
||||
glm::vec4 accumulated;
|
||||
// check for translucency
|
||||
int translucentPixels = 0;
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
const int RGB_BITS = 24;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb pixel = image.pixel(x, y);
|
||||
accumulated.r += qRed(pixel);
|
||||
accumulated.g += qGreen(pixel);
|
||||
accumulated.b += qBlue(pixel);
|
||||
|
||||
int alpha = qAlpha(pixel);
|
||||
int alpha = image.pixel(x, y) >> RGB_BITS;
|
||||
if (alpha != 0 && alpha != EIGHT_BIT_MAXIMUM) {
|
||||
translucentPixels++;
|
||||
}
|
||||
accumulated.a += alpha;
|
||||
}
|
||||
}
|
||||
int imageArea = image.width() * image.height();
|
||||
QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image),
|
||||
Q_ARG(const glm::vec4&, accumulated / (float) (imageArea * EIGHT_BIT_MAXIMUM)),
|
||||
Q_ARG(bool, translucentPixels >= imageArea / 2));
|
||||
_reply->deleteLater();
|
||||
}
|
||||
|
@ -327,8 +321,7 @@ void NetworkTexture::downloadFinished(QNetworkReply* reply) {
|
|||
QThreadPool::globalInstance()->start(new ImageReader(_self, reply));
|
||||
}
|
||||
|
||||
void NetworkTexture::setImage(const QImage& image, const glm::vec4& averageColor, bool translucent) {
|
||||
_averageColor = averageColor;
|
||||
void NetworkTexture::setImage(const QImage& image, bool translucent) {
|
||||
_translucent = translucent;
|
||||
|
||||
finishedLoading(true);
|
||||
|
@ -336,8 +329,7 @@ void NetworkTexture::setImage(const QImage& image, const glm::vec4& averageColor
|
|||
glBindTexture(GL_TEXTURE_2D, getID());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
|
@ -352,6 +344,33 @@ DilatableNetworkTexture::DilatableNetworkTexture(const QUrl& url) :
|
|||
{
|
||||
}
|
||||
|
||||
QSharedPointer<Texture> DilatableNetworkTexture::getDilatedTexture(float dilation) {
|
||||
QSharedPointer<Texture> texture = _dilatedTextures.value(dilation);
|
||||
if (texture.isNull()) {
|
||||
texture = QSharedPointer<Texture>(new Texture());
|
||||
|
||||
if (!_image.isNull()) {
|
||||
QImage dilatedImage = _image;
|
||||
QPainter painter;
|
||||
painter.begin(&dilatedImage);
|
||||
QPainterPath path;
|
||||
qreal radius = glm::mix((float) _innerRadius, (float) _outerRadius, dilation);
|
||||
path.addEllipse(QPointF(_image.width() / 2.0, _image.height() / 2.0), radius, radius);
|
||||
painter.fillPath(path, Qt::black);
|
||||
painter.end();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture->getID());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 1,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
_dilatedTextures.insert(dilation, texture);
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
void DilatableNetworkTexture::imageLoaded(const QImage& image) {
|
||||
_image = image;
|
||||
|
||||
|
@ -372,31 +391,8 @@ void DilatableNetworkTexture::imageLoaded(const QImage& image) {
|
|||
_dilatedTextures.clear();
|
||||
}
|
||||
|
||||
QSharedPointer<Texture> DilatableNetworkTexture::getDilatedTexture(float dilation) {
|
||||
QSharedPointer<Texture> texture = _dilatedTextures.value(dilation);
|
||||
if (texture.isNull()) {
|
||||
texture = QSharedPointer<Texture>(new Texture());
|
||||
|
||||
if (!_image.isNull()) {
|
||||
QImage dilatedImage = _image;
|
||||
QPainter painter;
|
||||
painter.begin(&dilatedImage);
|
||||
QPainterPath path;
|
||||
qreal radius = glm::mix((float) _innerRadius, (float) _outerRadius, dilation);
|
||||
path.addEllipse(QPointF(_image.width() / 2.0, _image.height() / 2.0), radius, radius);
|
||||
painter.fillPath(path, Qt::black);
|
||||
painter.end();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture->getID());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 1,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits());
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
_dilatedTextures.insert(dilation, texture);
|
||||
}
|
||||
return texture;
|
||||
void DilatableNetworkTexture::reinsert() {
|
||||
static_cast<TextureCache*>(_cache.data())->_dilatableNetworkTextures.insert(_url,
|
||||
qWeakPointerCast<NetworkTexture, Resource>(_self));
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,8 @@ protected:
|
|||
|
||||
private:
|
||||
|
||||
friend class DilatableNetworkTexture;
|
||||
|
||||
QOpenGLFramebufferObject* createFramebufferObject();
|
||||
|
||||
GLuint _permutationNormalTextureID;
|
||||
|
@ -117,9 +119,6 @@ public:
|
|||
|
||||
NetworkTexture(const QUrl& url, bool normalMap);
|
||||
|
||||
/// Returns the average color over the entire texture.
|
||||
const glm::vec4& getAverageColor() const { return _averageColor; }
|
||||
|
||||
/// Checks whether it "looks like" this texture is translucent
|
||||
/// (majority of pixels neither fully opaque or fully transparent).
|
||||
bool isTranslucent() const { return _translucent; }
|
||||
|
@ -129,11 +128,10 @@ protected:
|
|||
virtual void downloadFinished(QNetworkReply* reply);
|
||||
virtual void imageLoaded(const QImage& image);
|
||||
|
||||
Q_INVOKABLE void setImage(const QImage& image, const glm::vec4& averageColor, bool translucent);
|
||||
Q_INVOKABLE void setImage(const QImage& image, bool translucent);
|
||||
|
||||
private:
|
||||
|
||||
glm::vec4 _averageColor;
|
||||
bool _translucent;
|
||||
};
|
||||
|
||||
|
@ -151,6 +149,7 @@ public:
|
|||
protected:
|
||||
|
||||
virtual void imageLoaded(const QImage& image);
|
||||
virtual void reinsert();
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//
|
||||
|
||||
#ifndef __interface__starfield__Controller__
|
||||
#define __interface__starfield__Confroller__
|
||||
#define __interface__starfield__Controller__
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
using namespace starfield;
|
||||
|
||||
const float Generator::STAR_COLORIZATION = 0.1f;
|
||||
const float PI_OVER_180 = 3.14159265358979f / 180.f;
|
||||
|
||||
void Generator::computeStarPositions(InputVertices& destination, unsigned limit, unsigned seed) {
|
||||
InputVertices* vertices = & destination;
|
||||
|
@ -89,4 +90,4 @@ unsigned Generator::computeStarColor(float colorization) {
|
|||
red = green = blue = 2 + (rand() % 128);
|
||||
}
|
||||
return red | (green << 8) | (blue << 16);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -308,4 +308,4 @@ bool Renderer::TileSelection::deferred(Renderer::TileSelection::Cursor& cursor)
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
//
|
||||
// ChatEntry.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/24/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include "ChatEntry.h"
|
||||
#include "InterfaceConfig.h"
|
||||
#include "Util.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
const int MAX_CONTENT_LENGTH = 80;
|
||||
|
||||
ChatEntry::ChatEntry() : _cursorPos(0) {
|
||||
}
|
||||
|
||||
void ChatEntry::clear() {
|
||||
_contents.clear();
|
||||
_cursorPos = 0;
|
||||
}
|
||||
|
||||
bool ChatEntry::keyPressEvent(QKeyEvent* event) {
|
||||
event->accept();
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
return false;
|
||||
|
||||
case Qt::Key_Escape:
|
||||
clear();
|
||||
return false;
|
||||
|
||||
case Qt::Key_Backspace:
|
||||
if (_cursorPos != 0) {
|
||||
_contents.erase(_cursorPos - 1, 1);
|
||||
_cursorPos--;
|
||||
}
|
||||
return true;
|
||||
|
||||
case Qt::Key_Delete:
|
||||
if (_cursorPos < (int)_contents.size()) {
|
||||
_contents.erase(_cursorPos, 1);
|
||||
}
|
||||
return true;
|
||||
|
||||
case Qt::Key_Left:
|
||||
if (_cursorPos != 0) {
|
||||
_cursorPos--;
|
||||
}
|
||||
return true;
|
||||
|
||||
case Qt::Key_Right:
|
||||
if (_cursorPos != _contents.size()) {
|
||||
_cursorPos++;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
QString text = event->text();
|
||||
if (text.isEmpty()) {
|
||||
event->ignore();
|
||||
return true;
|
||||
}
|
||||
if (_contents.size() < MAX_CONTENT_LENGTH) {
|
||||
_contents.insert(_cursorPos, 1, text.at(0).toLatin1());
|
||||
_cursorPos++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const float ALL_WHITE[] = { 1.0f, 1.0f, 1.0f };
|
||||
|
||||
void ChatEntry::render(int screenWidth, int screenHeight) {
|
||||
// draw a gray background so that we can actually see what we're typing
|
||||
int bottom = screenHeight - 150, top = screenHeight - 165;
|
||||
int left = 20, right = left + 600;
|
||||
|
||||
glColor3f(0.2f, 0.2f, 0.2f);
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(left - 5, bottom + 7);
|
||||
glVertex2f(right + 5, bottom + 7);
|
||||
glVertex2f(right + 5, top - 3);
|
||||
glVertex2f(left - 5, top - 3);
|
||||
glEnd();
|
||||
|
||||
drawText(left, bottom, 0.10f, 0, 2, _contents.c_str(), ALL_WHITE);
|
||||
|
||||
float width = 0;
|
||||
for (string::iterator it = _contents.begin(), end = it + _cursorPos; it != end; it++) {
|
||||
width += widthChar(0.10f, 0, *it);
|
||||
}
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glVertex2f(left + width, top + 2);
|
||||
glVertex2f(left + width, bottom + 2);
|
||||
glEnd();
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
//
|
||||
// ChatEntry.h
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/24/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__ChatEntry__
|
||||
#define __interface__ChatEntry__
|
||||
|
||||
#include <string>
|
||||
|
||||
class QKeyEvent;
|
||||
|
||||
class ChatEntry {
|
||||
public:
|
||||
|
||||
ChatEntry();
|
||||
|
||||
const std::string& getContents() const { return _contents; }
|
||||
|
||||
void clear();
|
||||
|
||||
bool keyPressEvent(QKeyEvent* event);
|
||||
|
||||
void render(int screenWidth, int screenHeight);
|
||||
|
||||
private:
|
||||
|
||||
std::string _contents;
|
||||
int _cursorPos;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__ChatEntry__) */
|
220
interface/src/ui/ChatWindow.cpp
Normal file
220
interface/src/ui/ChatWindow.cpp
Normal file
|
@ -0,0 +1,220 @@
|
|||
//
|
||||
// ChatWindow.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Dimitar Dobrev on 3/6/14.
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QFrame>
|
||||
#include <QLayoutItem>
|
||||
#include <QPalette>
|
||||
#include <QScrollBar>
|
||||
#include <QSizePolicy>
|
||||
#include <QTextDocument>
|
||||
#include <QTimer>
|
||||
|
||||
#include "Application.h"
|
||||
#include "FlowLayout.h"
|
||||
#include "qtimespan.h"
|
||||
#include "ui_chatWindow.h"
|
||||
#include "XmppClient.h"
|
||||
|
||||
#include "ChatWindow.h"
|
||||
|
||||
const int NUM_MESSAGES_TO_TIME_STAMP = 20;
|
||||
|
||||
const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)");
|
||||
|
||||
ChatWindow::ChatWindow() :
|
||||
QDialog(Application::getInstance()->getGLWidget(), Qt::CustomizeWindowHint),
|
||||
ui(new Ui::ChatWindow),
|
||||
numMessagesAfterLastTimeStamp(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
|
||||
ui->usersWidget->setLayout(flowLayout);
|
||||
|
||||
ui->messagePlainTextEdit->installEventFilter(this);
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
if (xmppClient.isConnected()) {
|
||||
participantsChanged();
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
connect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
|
||||
ui->connectingToXMPPLabel->hide();
|
||||
startTimerForTimeStamps();
|
||||
} else {
|
||||
ui->numOnlineLabel->hide();
|
||||
ui->closeButton->hide();
|
||||
ui->usersWidget->hide();
|
||||
ui->messagesScrollArea->hide();
|
||||
ui->messagePlainTextEdit->hide();
|
||||
connect(&xmppClient, SIGNAL(connected()), this, SLOT(connected()));
|
||||
}
|
||||
connect(&xmppClient, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(messageReceived(QXmppMessage)));
|
||||
#endif
|
||||
}
|
||||
|
||||
ChatWindow::~ChatWindow() {
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
disconnect(&xmppClient, SIGNAL(connected()), this, SLOT(connected()));
|
||||
disconnect(&xmppClient, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(messageReceived(QXmppMessage)));
|
||||
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
disconnect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
|
||||
#endif
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ChatWindow::reject() {
|
||||
hide();
|
||||
}
|
||||
|
||||
bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
|
||||
Q_UNUSED(sender);
|
||||
|
||||
if (event->type() != QEvent::KeyPress) {
|
||||
return false;
|
||||
}
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) &&
|
||||
(keyEvent->modifiers() & Qt::ShiftModifier) == 0) {
|
||||
QString messageText = ui->messagePlainTextEdit->document()->toPlainText().trimmed();
|
||||
if (!messageText.isEmpty()) {
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
QXmppMessage message;
|
||||
message.setTo(publicChatRoom->jid());
|
||||
message.setType(QXmppMessage::GroupChat);
|
||||
message.setBody(messageText);
|
||||
XmppClient::getInstance().getXMPPClient().sendPacket(message);
|
||||
#endif
|
||||
ui->messagePlainTextEdit->document()->clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
QString ChatWindow::getParticipantName(const QString& participant) {
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
return participant.right(participant.count() - 1 - publicChatRoom->jid().count());
|
||||
}
|
||||
#endif
|
||||
|
||||
void ChatWindow::addTimeStamp() {
|
||||
QTimeSpan timePassed = QDateTime::currentDateTime() - lastMessageStamp;
|
||||
int times[] = { timePassed.daysPart(), timePassed.hoursPart(), timePassed.minutesPart() };
|
||||
QString strings[] = { tr("day", 0, times[0]), tr("hour", 0, times[1]), tr("minute", 0, times[2]) };
|
||||
QString timeString = "";
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (times[i] > 0) {
|
||||
timeString += strings[i] + " ";
|
||||
}
|
||||
}
|
||||
timeString.chop(1);
|
||||
if (!timeString.isEmpty()) {
|
||||
QLabel* timeLabel = new QLabel(timeString);
|
||||
timeLabel->setStyleSheet("color: palette(shadow);"
|
||||
"background-color: palette(highlight);"
|
||||
"padding: 4px;");
|
||||
timeLabel->setAlignment(Qt::AlignHCenter);
|
||||
ui->messagesFormLayout->addRow(timeLabel);
|
||||
numMessagesAfterLastTimeStamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWindow::startTimerForTimeStamps() {
|
||||
QTimer* timer = new QTimer(this);
|
||||
timer->setInterval(10 * 60 * 1000);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
|
||||
timer->start();
|
||||
}
|
||||
|
||||
void ChatWindow::connected() {
|
||||
ui->connectingToXMPPLabel->hide();
|
||||
ui->numOnlineLabel->show();
|
||||
ui->closeButton->show();
|
||||
ui->usersWidget->show();
|
||||
ui->messagesScrollArea->show();
|
||||
ui->messagePlainTextEdit->show();
|
||||
ui->messagePlainTextEdit->setFocus();
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
connect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
|
||||
#endif
|
||||
startTimerForTimeStamps();
|
||||
}
|
||||
|
||||
void ChatWindow::timeout() {
|
||||
if (numMessagesAfterLastTimeStamp >= NUM_MESSAGES_TO_TIME_STAMP) {
|
||||
addTimeStamp();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
|
||||
void ChatWindow::error(QXmppClient::Error error) {
|
||||
ui->connectingToXMPPLabel->setText(QString::number(error));
|
||||
}
|
||||
|
||||
void ChatWindow::participantsChanged() {
|
||||
QStringList participants = XmppClient::getInstance().getPublicChatRoom()->participants();
|
||||
ui->numOnlineLabel->setText(tr("%1 online now:").arg(participants.count()));
|
||||
|
||||
while (QLayoutItem* item = ui->usersWidget->layout()->takeAt(0)) {
|
||||
delete item->widget();
|
||||
delete item;
|
||||
}
|
||||
foreach (const QString& participant, participants) {
|
||||
QLabel* userLabel = new QLabel(getParticipantName(participant));
|
||||
userLabel->setStyleSheet("background-color: palette(light);"
|
||||
"border-radius: 5px;"
|
||||
"color: #267077;"
|
||||
"padding: 2px;"
|
||||
"border: 1px solid palette(shadow);"
|
||||
"font-weight: bold");
|
||||
ui->usersWidget->layout()->addWidget(userLabel);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWindow::messageReceived(const QXmppMessage& message) {
|
||||
if (message.type() != QXmppMessage::GroupChat) {
|
||||
return;
|
||||
}
|
||||
|
||||
QLabel* userLabel = new QLabel(getParticipantName(message.from()));
|
||||
userLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
userLabel->setStyleSheet("padding: 2px; font-weight: bold");
|
||||
userLabel->setAlignment(Qt::AlignTop);
|
||||
|
||||
QLabel* messageLabel = new QLabel(message.body().replace(regexLinks, "<a href=\"\\1\">\\1</a>"));
|
||||
messageLabel->setWordWrap(true);
|
||||
messageLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
messageLabel->setOpenExternalLinks(true);
|
||||
messageLabel->setStyleSheet("padding: 2px; margin-right: 20px");
|
||||
messageLabel->setAlignment(Qt::AlignTop);
|
||||
|
||||
ui->messagesFormLayout->addRow(userLabel, messageLabel);
|
||||
ui->messagesFormLayout->parentWidget()->updateGeometry();
|
||||
Application::processEvents();
|
||||
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
|
||||
verticalScrollBar->setSliderPosition(verticalScrollBar->maximum());
|
||||
messageLabel->updateGeometry();
|
||||
|
||||
++numMessagesAfterLastTimeStamp;
|
||||
if (message.stamp().isValid()) {
|
||||
lastMessageStamp = message.stamp().toLocalTime();
|
||||
} else {
|
||||
lastMessageStamp = QDateTime::currentDateTime();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
62
interface/src/ui/ChatWindow.h
Normal file
62
interface/src/ui/ChatWindow.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// ChatWindow.h
|
||||
// interface
|
||||
//
|
||||
// Created by Dimitar Dobrev on 3/6/14.
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__ChatWindow__
|
||||
#define __interface__ChatWindow__
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDateTime>
|
||||
#include <QTimer>
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
|
||||
#include <QXmppClient.h>
|
||||
#include <QXmppMessage.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace Ui {
|
||||
class ChatWindow;
|
||||
}
|
||||
|
||||
class ChatWindow : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ChatWindow();
|
||||
~ChatWindow();
|
||||
|
||||
virtual void reject();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* sender, QEvent* event);
|
||||
|
||||
private:
|
||||
#ifdef HAVE_QXMPP
|
||||
QString getParticipantName(const QString& participant);
|
||||
#endif
|
||||
void startTimerForTimeStamps();
|
||||
void addTimeStamp();
|
||||
|
||||
Ui::ChatWindow* ui;
|
||||
int numMessagesAfterLastTimeStamp;
|
||||
QDateTime lastMessageStamp;
|
||||
|
||||
private slots:
|
||||
void connected();
|
||||
void timeout();
|
||||
#ifdef HAVE_QXMPP
|
||||
void error(QXmppClient::Error error);
|
||||
void participantsChanged();
|
||||
void messageReceived(const QXmppMessage& message);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__ChatWindow__) */
|
213
interface/src/ui/FlowLayout.cpp
Normal file
213
interface/src/ui/FlowLayout.cpp
Normal file
|
@ -0,0 +1,213 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||
** of its contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "FlowLayout.h"
|
||||
//! [1]
|
||||
FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
|
||||
: QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
|
||||
{
|
||||
setContentsMargins(margin, margin, margin, margin);
|
||||
}
|
||||
|
||||
FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
|
||||
: m_hSpace(hSpacing), m_vSpace(vSpacing)
|
||||
{
|
||||
setContentsMargins(margin, margin, margin, margin);
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
FlowLayout::~FlowLayout()
|
||||
{
|
||||
QLayoutItem *item;
|
||||
while ((item = takeAt(0)))
|
||||
delete item;
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
void FlowLayout::addItem(QLayoutItem *item)
|
||||
{
|
||||
itemList.append(item);
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
int FlowLayout::horizontalSpacing() const
|
||||
{
|
||||
if (m_hSpace >= 0) {
|
||||
return m_hSpace;
|
||||
} else {
|
||||
return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
|
||||
}
|
||||
}
|
||||
|
||||
int FlowLayout::verticalSpacing() const
|
||||
{
|
||||
if (m_vSpace >= 0) {
|
||||
return m_vSpace;
|
||||
} else {
|
||||
return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
|
||||
}
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
int FlowLayout::count() const
|
||||
{
|
||||
return itemList.size();
|
||||
}
|
||||
|
||||
QLayoutItem *FlowLayout::itemAt(int index) const
|
||||
{
|
||||
return itemList.value(index);
|
||||
}
|
||||
|
||||
QLayoutItem *FlowLayout::takeAt(int index)
|
||||
{
|
||||
if (index >= 0 && index < itemList.size())
|
||||
return itemList.takeAt(index);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
Qt::Orientations FlowLayout::expandingDirections() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
bool FlowLayout::hasHeightForWidth() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int FlowLayout::heightForWidth(int width) const
|
||||
{
|
||||
int height = doLayout(QRect(0, 0, width, 0), true);
|
||||
return height;
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
void FlowLayout::setGeometry(const QRect &rect)
|
||||
{
|
||||
QLayout::setGeometry(rect);
|
||||
doLayout(rect, false);
|
||||
}
|
||||
|
||||
QSize FlowLayout::sizeHint() const
|
||||
{
|
||||
return minimumSize();
|
||||
}
|
||||
|
||||
QSize FlowLayout::minimumSize() const
|
||||
{
|
||||
QSize size;
|
||||
QLayoutItem *item;
|
||||
foreach (item, itemList)
|
||||
size = size.expandedTo(item->minimumSize());
|
||||
|
||||
size += QSize(2*margin(), 2*margin());
|
||||
return size;
|
||||
}
|
||||
//! [8]
|
||||
|
||||
//! [9]
|
||||
int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
|
||||
{
|
||||
int left, top, right, bottom;
|
||||
getContentsMargins(&left, &top, &right, &bottom);
|
||||
QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
|
||||
int x = effectiveRect.x();
|
||||
int y = effectiveRect.y();
|
||||
int lineHeight = 0;
|
||||
//! [9]
|
||||
|
||||
//! [10]
|
||||
QLayoutItem *item;
|
||||
foreach (item, itemList) {
|
||||
QWidget *wid = item->widget();
|
||||
int spaceX = horizontalSpacing();
|
||||
if (spaceX == -1)
|
||||
spaceX = wid->style()->layoutSpacing(
|
||||
QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
|
||||
int spaceY = verticalSpacing();
|
||||
if (spaceY == -1)
|
||||
spaceY = wid->style()->layoutSpacing(
|
||||
QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
|
||||
//! [10]
|
||||
//! [11]
|
||||
int nextX = x + item->sizeHint().width() + spaceX;
|
||||
if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
|
||||
x = effectiveRect.x();
|
||||
y = y + lineHeight + spaceY;
|
||||
nextX = x + item->sizeHint().width() + spaceX;
|
||||
lineHeight = 0;
|
||||
}
|
||||
|
||||
if (!testOnly)
|
||||
item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
|
||||
|
||||
x = nextX;
|
||||
lineHeight = qMax(lineHeight, item->sizeHint().height());
|
||||
}
|
||||
return y + lineHeight - rect.y() + bottom;
|
||||
}
|
||||
//! [11]
|
||||
//! [12]
|
||||
int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
|
||||
{
|
||||
QObject *parent = this->parent();
|
||||
if (!parent) {
|
||||
return -1;
|
||||
} else if (parent->isWidgetType()) {
|
||||
QWidget *pw = static_cast<QWidget *>(parent);
|
||||
return pw->style()->pixelMetric(pm, 0, pw);
|
||||
} else {
|
||||
return static_cast<QLayout *>(parent)->spacing();
|
||||
}
|
||||
}
|
||||
//! [12]
|
78
interface/src/ui/FlowLayout.h
Normal file
78
interface/src/ui/FlowLayout.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||
** of its contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef FLOWLAYOUT_H
|
||||
#define FLOWLAYOUT_H
|
||||
|
||||
#include <QLayout>
|
||||
#include <QRect>
|
||||
#include <QStyle>
|
||||
//! [0]
|
||||
class FlowLayout : public QLayout
|
||||
{
|
||||
public:
|
||||
explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
|
||||
explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
|
||||
~FlowLayout();
|
||||
|
||||
void addItem(QLayoutItem *item);
|
||||
int horizontalSpacing() const;
|
||||
int verticalSpacing() const;
|
||||
Qt::Orientations expandingDirections() const;
|
||||
bool hasHeightForWidth() const;
|
||||
int heightForWidth(int) const;
|
||||
int count() const;
|
||||
QLayoutItem *itemAt(int index) const;
|
||||
QSize minimumSize() const;
|
||||
void setGeometry(const QRect &rect);
|
||||
QSize sizeHint() const;
|
||||
QLayoutItem *takeAt(int index);
|
||||
|
||||
private:
|
||||
int doLayout(const QRect &rect, bool testOnly) const;
|
||||
int smartSpacing(QStyle::PixelMetric pm) const;
|
||||
|
||||
QList<QLayoutItem *> itemList;
|
||||
int m_hSpace;
|
||||
int m_vSpace;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // FLOWLAYOUT_H
|
|
@ -40,10 +40,12 @@ void LocalVoxelsOverlay::update(float deltatime) {
|
|||
_voxelSystem->init();
|
||||
}
|
||||
|
||||
if (_voxelCount != _tree->getOctreeElementsCount()) {
|
||||
_tree->lockForRead();
|
||||
if (_visible && _voxelCount != _tree->getOctreeElementsCount()) {
|
||||
_voxelCount = _tree->getOctreeElementsCount();
|
||||
_voxelSystem->forceRedrawEntireTree();
|
||||
}
|
||||
_tree->unlock();
|
||||
}
|
||||
|
||||
void LocalVoxelsOverlay::render() {
|
||||
|
@ -59,8 +61,11 @@ void LocalVoxelsOverlay::render() {
|
|||
void LocalVoxelsOverlay::setProperties(const QScriptValue &properties) {
|
||||
Volume3DOverlay::setProperties(properties);
|
||||
|
||||
if (properties.property("scale").isValid()) {
|
||||
setSize(properties.property("scale").toVariant().toFloat());
|
||||
}
|
||||
|
||||
QScriptValue treeName = properties.property("name");
|
||||
// if "end" property was not there, check to see if they included aliases: endPoint, or p2
|
||||
if (treeName.isValid()) {
|
||||
if ((_treeName = treeName.toString()) == DOMAIN_TREE_NAME) {
|
||||
qDebug() << "addOverlay(): Can't create overlay from domain tree";
|
||||
|
|
|
@ -68,7 +68,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
const unsigned redish = 0xfff00000;
|
||||
palette.setColor(QPalette::WindowText, QColor::fromRgb(redish));
|
||||
_feedback->setPalette(palette);
|
||||
_feedback->setText(getFeedbackText());
|
||||
_feedback->setText(Menu::getInstance()->getLODFeedbackText());
|
||||
const int FEEDBACK_WIDTH = 350;
|
||||
_feedback->setFixedWidth(FEEDBACK_WIDTH);
|
||||
form->addRow("You can see... ", _feedback);
|
||||
|
@ -81,40 +81,6 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
this->QDialog::setLayout(form);
|
||||
}
|
||||
|
||||
QString LodToolsDialog::getFeedbackText() {
|
||||
// determine granularity feedback
|
||||
int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust();
|
||||
QString granularityFeedback;
|
||||
|
||||
switch (boundaryLevelAdjust) {
|
||||
case 0: {
|
||||
granularityFeedback = QString("at standard granularity.");
|
||||
} break;
|
||||
case 1: {
|
||||
granularityFeedback = QString("at half of standard granularity.");
|
||||
} break;
|
||||
case 2: {
|
||||
granularityFeedback = QString("at a third of standard granularity.");
|
||||
} break;
|
||||
default: {
|
||||
granularityFeedback = QString("at 1/%1th of standard granularity.").arg(boundaryLevelAdjust + 1);
|
||||
} break;
|
||||
}
|
||||
|
||||
// distance feedback
|
||||
float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale();
|
||||
float relativeToDefault = voxelSizeScale / DEFAULT_OCTREE_SIZE_SCALE;
|
||||
QString result;
|
||||
if (relativeToDefault > 1.01) {
|
||||
result = QString("%1 further %2").arg(relativeToDefault,8,'f',2).arg(granularityFeedback);
|
||||
} else if (relativeToDefault > 0.99) {
|
||||
result = QString("the default distance %1").arg(granularityFeedback);
|
||||
} else {
|
||||
result = QString("%1 of default %2").arg(relativeToDefault,8,'f',3).arg(granularityFeedback);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LodToolsDialog::~LodToolsDialog() {
|
||||
delete _feedback;
|
||||
delete _lodSize;
|
||||
|
@ -124,19 +90,19 @@ LodToolsDialog::~LodToolsDialog() {
|
|||
void LodToolsDialog::reloadSliders() {
|
||||
_lodSize->setValue(Menu::getInstance()->getVoxelSizeScale() / TREE_SCALE);
|
||||
_boundaryLevelAdjust->setValue(Menu::getInstance()->getBoundaryLevelAdjust());
|
||||
_feedback->setText(getFeedbackText());
|
||||
_feedback->setText(Menu::getInstance()->getLODFeedbackText());
|
||||
}
|
||||
|
||||
void LodToolsDialog::sizeScaleValueChanged(int value) {
|
||||
float realValue = value * TREE_SCALE;
|
||||
Menu::getInstance()->setVoxelSizeScale(realValue);
|
||||
|
||||
_feedback->setText(getFeedbackText());
|
||||
_feedback->setText(Menu::getInstance()->getLODFeedbackText());
|
||||
}
|
||||
|
||||
void LodToolsDialog::boundaryLevelValueChanged(int value) {
|
||||
Menu::getInstance()->setBoundaryLevelAdjust(value);
|
||||
_feedback->setText(getFeedbackText());
|
||||
_feedback->setText(Menu::getInstance()->getLODFeedbackText());
|
||||
}
|
||||
|
||||
void LodToolsDialog::resetClicked(bool checked) {
|
||||
|
|
|
@ -36,8 +36,6 @@ protected:
|
|||
void closeEvent(QCloseEvent*);
|
||||
|
||||
private:
|
||||
QString getFeedbackText();
|
||||
|
||||
QSlider* _lodSize;
|
||||
QSlider* _boundaryLevelAdjust;
|
||||
QLabel* _feedback;
|
||||
|
|
|
@ -100,6 +100,7 @@ MetavoxelEditor::MetavoxelEditor() :
|
|||
addTool(new InsertSpannerTool(this));
|
||||
addTool(new RemoveSpannerTool(this));
|
||||
addTool(new ClearSpannersTool(this));
|
||||
addTool(new SetSpannerTool(this));
|
||||
|
||||
updateAttributes();
|
||||
|
||||
|
@ -138,11 +139,11 @@ glm::quat MetavoxelEditor::getGridRotation() const {
|
|||
return glm::quat();
|
||||
|
||||
case GRID_PLANE_XZ:
|
||||
return glm::angleAxis(-90.0f, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
return glm::angleAxis(-PI_OVER_TWO, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
|
||||
case GRID_PLANE_YZ:
|
||||
default:
|
||||
return glm::angleAxis(90.0f, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
return glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,18 +270,19 @@ const float GRID_BRIGHTNESS = 0.5f;
|
|||
|
||||
void MetavoxelEditor::render() {
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
MetavoxelTool* tool = getActiveTool();
|
||||
if (tool) {
|
||||
tool->render();
|
||||
}
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glm::quat rotation = getGridRotation();
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
|
||||
MetavoxelTool* tool = getActiveTool();
|
||||
if (tool) {
|
||||
tool->render();
|
||||
}
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
glLineWidth(1.0f);
|
||||
|
||||
|
@ -370,12 +372,23 @@ BoxSetTool::BoxSetTool(MetavoxelEditor* editor) :
|
|||
}
|
||||
|
||||
void BoxSetTool::render() {
|
||||
if (Application::getInstance()->isMouseHidden()) {
|
||||
resetState();
|
||||
return;
|
||||
}
|
||||
QString selected = _editor->getSelectedAttribute();
|
||||
if (selected.isNull()) {
|
||||
resetState();
|
||||
return;
|
||||
}
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glm::quat rotation = _editor->getGridRotation();
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
glm::quat inverseRotation = glm::inverse(rotation);
|
||||
glm::vec3 rayOrigin = inverseRotation * Application::getInstance()->getMouseRayOrigin();
|
||||
glm::vec3 rayDirection = inverseRotation * Application::getInstance()->getMouseRayDirection();
|
||||
|
@ -439,6 +452,8 @@ void BoxSetTool::render() {
|
|||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
bool BoxSetTool::eventFilter(QObject* watched, QEvent* event) {
|
||||
|
@ -515,20 +530,18 @@ void GlobalSetTool::apply() {
|
|||
Application::getInstance()->getMetavoxels()->applyEdit(message);
|
||||
}
|
||||
|
||||
InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) :
|
||||
MetavoxelTool(editor, "Insert Spanner") {
|
||||
PlaceSpannerTool::PlaceSpannerTool(MetavoxelEditor* editor, const QString& name, const QString& placeText) :
|
||||
MetavoxelTool(editor, name) {
|
||||
|
||||
QPushButton* button = new QPushButton("Insert");
|
||||
QPushButton* button = new QPushButton(placeText);
|
||||
layout()->addWidget(button);
|
||||
connect(button, SIGNAL(clicked()), SLOT(insert()));
|
||||
connect(button, SIGNAL(clicked()), SLOT(place()));
|
||||
}
|
||||
|
||||
void InsertSpannerTool::simulate(float deltaTime) {
|
||||
SharedObjectPointer spanner = _editor->getValue().value<SharedObjectPointer>();
|
||||
static_cast<Spanner*>(spanner.data())->getRenderer()->simulate(deltaTime);
|
||||
}
|
||||
|
||||
void InsertSpannerTool::render() {
|
||||
void PlaceSpannerTool::simulate(float deltaTime) {
|
||||
if (Application::getInstance()->isMouseHidden()) {
|
||||
return;
|
||||
}
|
||||
_editor->detachValue();
|
||||
Spanner* spanner = static_cast<Spanner*>(_editor->getValue().value<SharedObjectPointer>().data());
|
||||
Transformable* transformable = qobject_cast<Transformable*>(spanner);
|
||||
|
@ -543,43 +556,70 @@ void InsertSpannerTool::render() {
|
|||
|
||||
transformable->setTranslation(rotation * glm::vec3(glm::vec2(rayOrigin + rayDirection * distance), position));
|
||||
}
|
||||
spanner->getRenderer()->simulate(deltaTime);
|
||||
}
|
||||
|
||||
void PlaceSpannerTool::render() {
|
||||
if (Application::getInstance()->isMouseHidden()) {
|
||||
return;
|
||||
}
|
||||
Spanner* spanner = static_cast<Spanner*>(_editor->getValue().value<SharedObjectPointer>().data());
|
||||
const float SPANNER_ALPHA = 0.25f;
|
||||
spanner->getRenderer()->render(SPANNER_ALPHA);
|
||||
}
|
||||
|
||||
bool InsertSpannerTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute->inherits("SharedObjectSetAttribute");
|
||||
bool PlaceSpannerTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute->inherits("SpannerSetAttribute");
|
||||
}
|
||||
|
||||
bool InsertSpannerTool::eventFilter(QObject* watched, QEvent* event) {
|
||||
bool PlaceSpannerTool::eventFilter(QObject* watched, QEvent* event) {
|
||||
if (event->type() == QEvent::MouseButtonPress) {
|
||||
insert();
|
||||
place();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void InsertSpannerTool::insert() {
|
||||
void PlaceSpannerTool::place() {
|
||||
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute());
|
||||
if (!attribute) {
|
||||
return;
|
||||
}
|
||||
SharedObjectPointer spanner = _editor->getValue().value<SharedObjectPointer>();
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(InsertSpannerEdit(attribute, spanner)) };
|
||||
MetavoxelEditMessage message = { createEdit(attribute, spanner) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message);
|
||||
}
|
||||
|
||||
InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) :
|
||||
PlaceSpannerTool(editor, "Insert Spanner", "Insert") {
|
||||
}
|
||||
|
||||
QVariant InsertSpannerTool::createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) {
|
||||
return QVariant::fromValue(InsertSpannerEdit(attribute, spanner));
|
||||
}
|
||||
|
||||
RemoveSpannerTool::RemoveSpannerTool(MetavoxelEditor* editor) :
|
||||
MetavoxelTool(editor, "Remove Spanner", false) {
|
||||
}
|
||||
|
||||
bool RemoveSpannerTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute->inherits("SharedObjectSetAttribute");
|
||||
return attribute->inherits("SpannerSetAttribute");
|
||||
}
|
||||
|
||||
bool RemoveSpannerTool::eventFilter(QObject* watched, QEvent* event) {
|
||||
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute());
|
||||
if (!attribute) {
|
||||
return false;
|
||||
}
|
||||
if (event->type() == QEvent::MouseButtonPress) {
|
||||
|
||||
float distance;
|
||||
SharedObjectPointer spanner = Application::getInstance()->getMetavoxels()->findFirstRaySpannerIntersection(
|
||||
Application::getInstance()->getMouseRayOrigin(), Application::getInstance()->getMouseRayDirection(),
|
||||
attribute, distance);
|
||||
if (spanner) {
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(RemoveSpannerEdit(attribute, spanner->getRemoteID())) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -594,7 +634,7 @@ ClearSpannersTool::ClearSpannersTool(MetavoxelEditor* editor) :
|
|||
}
|
||||
|
||||
bool ClearSpannersTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute->inherits("SharedObjectSetAttribute");
|
||||
return attribute->inherits("SpannerSetAttribute");
|
||||
}
|
||||
|
||||
void ClearSpannersTool::clear() {
|
||||
|
@ -605,3 +645,16 @@ void ClearSpannersTool::clear() {
|
|||
MetavoxelEditMessage message = { QVariant::fromValue(ClearSpannersEdit(attribute)) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message);
|
||||
}
|
||||
|
||||
SetSpannerTool::SetSpannerTool(MetavoxelEditor* editor) :
|
||||
PlaceSpannerTool(editor, "Set Spanner", "Set") {
|
||||
}
|
||||
|
||||
bool SetSpannerTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute == AttributeRegistry::getInstance()->getSpannersAttribute();
|
||||
}
|
||||
|
||||
QVariant SetSpannerTool::createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) {
|
||||
static_cast<Spanner*>(spanner.data())->setGranularity(_editor->getGridSpacing());
|
||||
return QVariant::fromValue(SetSpannerEdit(spanner));
|
||||
}
|
||||
|
|
|
@ -139,13 +139,13 @@ private slots:
|
|||
void apply();
|
||||
};
|
||||
|
||||
/// Allows inserting a spanner into the scene.
|
||||
class InsertSpannerTool : public MetavoxelTool {
|
||||
/// Base class for insert/set spanner tools.
|
||||
class PlaceSpannerTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
InsertSpannerTool(MetavoxelEditor* editor);
|
||||
PlaceSpannerTool(MetavoxelEditor* editor, const QString& name, const QString& placeText);
|
||||
|
||||
virtual void simulate(float deltaTime);
|
||||
|
||||
|
@ -155,9 +155,26 @@ public:
|
|||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) = 0;
|
||||
|
||||
private slots:
|
||||
|
||||
void insert();
|
||||
void place();
|
||||
};
|
||||
|
||||
/// Allows inserting a spanner into the scene.
|
||||
class InsertSpannerTool : public PlaceSpannerTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
InsertSpannerTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner);
|
||||
};
|
||||
|
||||
/// Allows removing a spanner from the scene.
|
||||
|
@ -188,4 +205,19 @@ private slots:
|
|||
void clear();
|
||||
};
|
||||
|
||||
/// Allows setting the value by placing a spanner.
|
||||
class SetSpannerTool : public PlaceSpannerTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
SetSpannerTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner);
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__MetavoxelEditor__) */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// VoxelStatsDialog.cpp
|
||||
// OctreeStatsDialog.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 7/19/13.
|
||||
|
@ -14,13 +14,13 @@
|
|||
#include <QPalette>
|
||||
#include <QColor>
|
||||
|
||||
#include <VoxelSceneStats.h>
|
||||
#include <OctreeSceneStats.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include "ui/VoxelStatsDialog.h"
|
||||
#include "ui/OctreeStatsDialog.h"
|
||||
|
||||
VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, NodeToVoxelSceneStats* model) :
|
||||
OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* model) :
|
||||
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint),
|
||||
_model(model) {
|
||||
|
||||
|
@ -52,7 +52,7 @@ VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, NodeToVoxelSceneStats* model
|
|||
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||
}
|
||||
|
||||
void VoxelStatsDialog::RemoveStatItem(int item) {
|
||||
void OctreeStatsDialog::RemoveStatItem(int item) {
|
||||
QLabel* myLabel = _labels[item];
|
||||
QWidget* automaticLabel = _form->labelForField(myLabel);
|
||||
_form->removeWidget(myLabel);
|
||||
|
@ -62,7 +62,7 @@ void VoxelStatsDialog::RemoveStatItem(int item) {
|
|||
_labels[item] = NULL;
|
||||
}
|
||||
|
||||
void VoxelStatsDialog::moreless(const QString& link) {
|
||||
void OctreeStatsDialog::moreless(const QString& link) {
|
||||
QStringList linkDetails = link.split("-");
|
||||
const int COMMAND_ITEM = 0;
|
||||
const int SERVER_NUMBER_ITEM = 1;
|
||||
|
@ -80,7 +80,7 @@ void VoxelStatsDialog::moreless(const QString& link) {
|
|||
}
|
||||
|
||||
|
||||
int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) {
|
||||
int OctreeStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) {
|
||||
char strBuf[64];
|
||||
const int STATS_LABEL_WIDTH = 600;
|
||||
|
||||
|
@ -109,13 +109,13 @@ int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) {
|
|||
return _statCount;
|
||||
}
|
||||
|
||||
VoxelStatsDialog::~VoxelStatsDialog() {
|
||||
OctreeStatsDialog::~OctreeStatsDialog() {
|
||||
for (int i = 0; i < _statCount; i++) {
|
||||
delete _labels[i];
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelStatsDialog::paintEvent(QPaintEvent* event) {
|
||||
void OctreeStatsDialog::paintEvent(QPaintEvent* event) {
|
||||
|
||||
// Update labels
|
||||
|
||||
|
@ -157,9 +157,9 @@ void VoxelStatsDialog::paintEvent(QPaintEvent* event) {
|
|||
|
||||
statsValue.str("");
|
||||
statsValue <<
|
||||
"Total: " << localTotalString.toLocal8Bit().constData() << " / " <<
|
||||
"Internal: " << localInternalString.toLocal8Bit().constData() << " / " <<
|
||||
"Leaves: " << localLeavesString.toLocal8Bit().constData() << "";
|
||||
"Total: " << qPrintable(localTotalString) << " / " <<
|
||||
"Internal: " << qPrintable(localInternalString) << " / " <<
|
||||
"Leaves: " << qPrintable(localLeavesString) << "";
|
||||
label->setText(statsValue.str().c_str());
|
||||
|
||||
// iterate all the current voxel stats, and list their sending modes, total their voxels, etc...
|
||||
|
@ -171,11 +171,11 @@ void VoxelStatsDialog::paintEvent(QPaintEvent* event) {
|
|||
unsigned long totalInternal = 0;
|
||||
unsigned long totalLeaves = 0;
|
||||
|
||||
Application::getInstance()->lockVoxelSceneStats();
|
||||
NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getOcteeSceneStats();
|
||||
for(NodeToVoxelSceneStatsIterator i = sceneStats->begin(); i != sceneStats->end(); i++) {
|
||||
Application::getInstance()->lockOctreeSceneStats();
|
||||
NodeToOctreeSceneStats* sceneStats = Application::getInstance()->getOcteeSceneStats();
|
||||
for(NodeToOctreeSceneStatsIterator i = sceneStats->begin(); i != sceneStats->end(); i++) {
|
||||
//const QUuid& uuid = i->first;
|
||||
VoxelSceneStats& stats = i->second;
|
||||
OctreeSceneStats& stats = i->second;
|
||||
serverCount++;
|
||||
|
||||
// calculate server node totals
|
||||
|
@ -194,7 +194,7 @@ void VoxelStatsDialog::paintEvent(QPaintEvent* event) {
|
|||
sendingMode << "S";
|
||||
}
|
||||
}
|
||||
Application::getInstance()->unlockVoxelSceneStats();
|
||||
Application::getInstance()->unlockOctreeSceneStats();
|
||||
sendingMode << " - " << serverCount << " servers";
|
||||
if (movingServerCount > 0) {
|
||||
sendingMode << " <SCENE NOT STABLE>";
|
||||
|
@ -212,16 +212,16 @@ void VoxelStatsDialog::paintEvent(QPaintEvent* event) {
|
|||
label = _labels[_serverVoxels];
|
||||
statsValue.str("");
|
||||
statsValue <<
|
||||
"Total: " << serversTotalString.toLocal8Bit().constData() << " / " <<
|
||||
"Internal: " << serversInternalString.toLocal8Bit().constData() << " / " <<
|
||||
"Leaves: " << serversLeavesString.toLocal8Bit().constData() << "";
|
||||
"Total: " << qPrintable(serversTotalString) << " / " <<
|
||||
"Internal: " << qPrintable(serversInternalString) << " / " <<
|
||||
"Leaves: " << qPrintable(serversLeavesString) << "";
|
||||
label->setText(statsValue.str().c_str());
|
||||
|
||||
showAllOctreeServers();
|
||||
|
||||
this->QDialog::paintEvent(event);
|
||||
}
|
||||
void VoxelStatsDialog::showAllOctreeServers() {
|
||||
void OctreeStatsDialog::showAllOctreeServers() {
|
||||
int serverCount = 0;
|
||||
|
||||
showOctreeServersOfType(serverCount, NodeType::VoxelServer, "Voxel",
|
||||
|
@ -239,7 +239,7 @@ void VoxelStatsDialog::showAllOctreeServers() {
|
|||
}
|
||||
}
|
||||
|
||||
void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName,
|
||||
void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName,
|
||||
NodeToJurisdictionMap& serverJurisdictions) {
|
||||
|
||||
QLocale locale(QLocale::English);
|
||||
|
@ -290,7 +290,7 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serv
|
|||
AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
|
||||
serverBounds.scale(TREE_SCALE);
|
||||
serverDetails << " jurisdiction: "
|
||||
<< rootCodeHex.toLocal8Bit().constData()
|
||||
<< qPrintable(rootCodeHex)
|
||||
<< " ["
|
||||
<< rootDetails.x << ", "
|
||||
<< rootDetails.y << ", "
|
||||
|
@ -303,10 +303,10 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serv
|
|||
|
||||
// now lookup stats details for this server...
|
||||
if (_extraServerDetails[serverCount-1] != LESS) {
|
||||
Application::getInstance()->lockVoxelSceneStats();
|
||||
NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getOcteeSceneStats();
|
||||
Application::getInstance()->lockOctreeSceneStats();
|
||||
NodeToOctreeSceneStats* sceneStats = Application::getInstance()->getOcteeSceneStats();
|
||||
if (sceneStats->find(nodeUUID) != sceneStats->end()) {
|
||||
VoxelSceneStats& stats = sceneStats->at(nodeUUID);
|
||||
OctreeSceneStats& stats = sceneStats->at(nodeUUID);
|
||||
|
||||
switch (_extraServerDetails[serverCount-1]) {
|
||||
case MOST: {
|
||||
|
@ -315,17 +315,29 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serv
|
|||
const unsigned long USECS_PER_MSEC = 1000;
|
||||
float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC;
|
||||
float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC;
|
||||
float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND;
|
||||
float lastFullPackets = stats.getLastFullTotalPackets();
|
||||
float lastFullPPS = lastFullPackets;
|
||||
if (lastFullSendInSeconds > 0) {
|
||||
lastFullPPS = lastFullPackets / lastFullSendInSeconds;
|
||||
}
|
||||
|
||||
QString lastFullEncodeString = locale.toString(lastFullEncode);
|
||||
QString lastFullSendString = locale.toString(lastFullSend);
|
||||
QString lastFullPacketsString = locale.toString(lastFullPackets);
|
||||
QString lastFullBytesString = locale.toString((uint)stats.getLastFullTotalBytes());
|
||||
QString lastFullPPSString = locale.toString(lastFullPPS);
|
||||
|
||||
extraDetails << "<br/>" << "Last Full Scene... " <<
|
||||
"Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " <<
|
||||
"Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms ";
|
||||
"Encode: " << qPrintable(lastFullEncodeString) << " ms " <<
|
||||
"Send: " << qPrintable(lastFullSendString) << " ms " <<
|
||||
"Packets: " << qPrintable(lastFullPacketsString) << " " <<
|
||||
"Bytes: " << qPrintable(lastFullBytesString) << " " <<
|
||||
"Rate: " << qPrintable(lastFullPPSString) << " PPS";
|
||||
|
||||
for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) {
|
||||
VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i);
|
||||
VoxelSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item);
|
||||
for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) {
|
||||
OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i);
|
||||
OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item);
|
||||
extraDetails << "<br/>" << itemInfo.caption << " " << stats.getItemValue(item);
|
||||
}
|
||||
} // fall through... since MOST has all of MORE
|
||||
|
@ -334,42 +346,51 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serv
|
|||
QString internalString = locale.toString((uint)stats.getTotalInternal());
|
||||
QString leavesString = locale.toString((uint)stats.getTotalLeaves());
|
||||
|
||||
serverDetails << "<br/>" << "Node UUID: " <<
|
||||
nodeUUID.toString().toLocal8Bit().constData() << " ";
|
||||
serverDetails << "<br/>" << "Node UUID: " << qPrintable(nodeUUID.toString()) << " ";
|
||||
|
||||
serverDetails << "<br/>" << "Voxels: " <<
|
||||
totalString.toLocal8Bit().constData() << " total " <<
|
||||
internalString.toLocal8Bit().constData() << " internal " <<
|
||||
leavesString.toLocal8Bit().constData() << " leaves ";
|
||||
qPrintable(totalString) << " total " <<
|
||||
qPrintable(internalString) << " internal " <<
|
||||
qPrintable(leavesString) << " leaves ";
|
||||
|
||||
QString incomingPacketsString = locale.toString((uint)stats.getIncomingPackets());
|
||||
QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes());
|
||||
QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes());
|
||||
QString incomingOutOfOrderString = locale.toString((uint)stats.getIncomingOutOfOrder());
|
||||
QString incomingLateString = locale.toString((uint)stats.getIncomingLate());
|
||||
QString incomingReallyLateString = locale.toString((uint)stats.getIncomingReallyLate());
|
||||
QString incomingEarlyString = locale.toString((uint)stats.getIncomingEarly());
|
||||
QString incomingLikelyLostString = locale.toString((uint)stats.getIncomingLikelyLost());
|
||||
QString incomingRecovered = locale.toString((uint)stats.getIncomingRecovered());
|
||||
QString incomingDuplicateString = locale.toString((uint)stats.getIncomingPossibleDuplicate());
|
||||
|
||||
int clockSkewInMS = node->getClockSkewUsec() / (int)USECS_PER_MSEC;
|
||||
QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage());
|
||||
QString incomingPingTimeString = locale.toString(node->getPingMs());
|
||||
QString incomingClockSkewString = locale.toString(clockSkewInMS);
|
||||
|
||||
serverDetails << "<br/>" << "Incoming Packets: " <<
|
||||
incomingPacketsString.toLocal8Bit().constData() <<
|
||||
" Out of Order: " << incomingOutOfOrderString.toLocal8Bit().constData() <<
|
||||
" Likely Lost: " << incomingLikelyLostString.toLocal8Bit().constData();
|
||||
serverDetails << "<br/>" << "Incoming Packets: " << qPrintable(incomingPacketsString) <<
|
||||
"/ Lost: " << qPrintable(incomingLikelyLostString) <<
|
||||
"/ Recovered: " << qPrintable(incomingRecovered);
|
||||
|
||||
serverDetails << "<br/>" << " Out of Order: " << qPrintable(incomingOutOfOrderString) <<
|
||||
"/ Early: " << qPrintable(incomingEarlyString) <<
|
||||
"/ Late: " << qPrintable(incomingLateString) <<
|
||||
"/ Really Late: " << qPrintable(incomingReallyLateString) <<
|
||||
"/ Duplicate: " << qPrintable(incomingDuplicateString);
|
||||
|
||||
serverDetails << "<br/>" <<
|
||||
" Average Flight Time: " << incomingFlightTimeString.toLocal8Bit().constData() << " msecs";
|
||||
" Average Flight Time: " << qPrintable(incomingFlightTimeString) << " msecs";
|
||||
|
||||
serverDetails << "<br/>" <<
|
||||
" Average Ping Time: " << incomingPingTimeString.toLocal8Bit().constData() << " msecs";
|
||||
" Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs";
|
||||
|
||||
serverDetails << "<br/>" <<
|
||||
" Average Clock Skew: " << incomingClockSkewString.toLocal8Bit().constData() << " msecs";
|
||||
|
||||
" Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs";
|
||||
|
||||
serverDetails << "<br/>" << "Incoming" <<
|
||||
" Bytes: " << incomingBytesString.toLocal8Bit().constData() <<
|
||||
" Wasted Bytes: " << incomingWastedBytesString.toLocal8Bit().constData();
|
||||
" Bytes: " << qPrintable(incomingBytesString) <<
|
||||
" Wasted Bytes: " << qPrintable(incomingWastedBytesString);
|
||||
|
||||
serverDetails << extraDetails.str();
|
||||
if (_extraServerDetails[serverCount-1] == MORE) {
|
||||
|
@ -386,7 +407,7 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serv
|
|||
} break;
|
||||
}
|
||||
}
|
||||
Application::getInstance()->unlockVoxelSceneStats();
|
||||
Application::getInstance()->unlockOctreeSceneStats();
|
||||
} else {
|
||||
linkDetails << " " << " [<a href='more-" << serverCount << "'>more...</a>]";
|
||||
linkDetails << " " << " [<a href='most-" << serverCount << "'>most...</a>]";
|
||||
|
@ -397,12 +418,12 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serv
|
|||
}
|
||||
}
|
||||
|
||||
void VoxelStatsDialog::reject() {
|
||||
void OctreeStatsDialog::reject() {
|
||||
// Just regularly close upon ESC
|
||||
this->QDialog::close();
|
||||
}
|
||||
|
||||
void VoxelStatsDialog::closeEvent(QCloseEvent* event) {
|
||||
void OctreeStatsDialog::closeEvent(QCloseEvent* event) {
|
||||
this->QDialog::closeEvent(event);
|
||||
emit closed();
|
||||
}
|
|
@ -1,30 +1,30 @@
|
|||
//
|
||||
// VoxelStatsDialog.h
|
||||
// OctreeStatsDialog.h
|
||||
// interface
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 7/19/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__VoxelStatsDialog__
|
||||
#define __hifi__VoxelStatsDialog__
|
||||
#ifndef __hifi__OctreeStatsDialog__
|
||||
#define __hifi__OctreeStatsDialog__
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFormLayout>
|
||||
#include <QLabel>
|
||||
|
||||
#include <VoxelSceneStats.h>
|
||||
#include <OctreeSceneStats.h>
|
||||
|
||||
#define MAX_STATS 100
|
||||
#define MAX_VOXEL_SERVERS 50
|
||||
#define DEFAULT_COLOR 0
|
||||
|
||||
class VoxelStatsDialog : public QDialog {
|
||||
class OctreeStatsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
// Sets up the UI
|
||||
VoxelStatsDialog(QWidget* parent, NodeToVoxelSceneStats* model);
|
||||
~VoxelStatsDialog();
|
||||
OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* model);
|
||||
~OctreeStatsDialog();
|
||||
|
||||
signals:
|
||||
void closed();
|
||||
|
@ -53,7 +53,7 @@ private:
|
|||
|
||||
QFormLayout* _form;
|
||||
QLabel* _labels[MAX_STATS];
|
||||
NodeToVoxelSceneStats* _model;
|
||||
NodeToOctreeSceneStats* _model;
|
||||
int _statCount;
|
||||
|
||||
int _sendingMode;
|
||||
|
@ -66,5 +66,5 @@ private:
|
|||
details _extraServerDetails[MAX_VOXEL_SERVERS];
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__VoxelStatsDialog__) */
|
||||
#endif /* defined(__interface__OctreeStatsDialog__) */
|
||||
|
|
@ -9,10 +9,6 @@
|
|||
#ifndef __interface__world__
|
||||
#define __interface__world__
|
||||
|
||||
#ifndef PIf
|
||||
#define PIf 3.14159265f
|
||||
#endif
|
||||
|
||||
const float GRAVITY_EARTH = 9.80665f;
|
||||
const float EDGE_SIZE_GROUND_PLANE = 20.f;
|
||||
|
||||
|
|
201
interface/ui/chatWindow.ui
Normal file
201
interface/ui/chatWindow.ui
Normal file
|
@ -0,0 +1,201 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ChatWindow</class>
|
||||
<widget class="QDialog" name="ChatWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>608</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Chat</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="connectingToXMPPLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Connecting to XMPP...</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="numOnlineLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font-weight: bold; color: palette(shadow); margin-bottom: 4px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> online now:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="closeButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/resources.qrc">
|
||||
<normaloff>:/images/close.svg</normaloff>:/images/close.svg</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="usersWidget" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="messagesScrollArea">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">margin-top: 12px; font-family: Helvetica, Arial, sans-serif;</string>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>358</width>
|
||||
<height>452</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">margin-top: 0px;</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="messagesFormLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="messagePlainTextEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="tabChangesFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>messagePlainTextEdit</tabstop>
|
||||
<tabstop>messagesScrollArea</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../resources/resources.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>closeButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>ChatWindow</receiver>
|
||||
<slot>hide()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>390</x>
|
||||
<y>42</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>550</x>
|
||||
<y>42</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -41,7 +41,7 @@ Sound::Sound(float volume, float frequency, float duration, float decay, QObject
|
|||
int numSamples = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; // we add sounds in chunks of this many samples
|
||||
|
||||
int chunkStartingSample = 0;
|
||||
float waveFrequency = (frequency / SAMPLE_RATE) * PI_TIMES_TWO;
|
||||
float waveFrequency = (frequency / SAMPLE_RATE) * TWO_PI;
|
||||
while (volume > 0.f) {
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
t = (float)chunkStartingSample + (float)i;
|
||||
|
|
|
@ -26,16 +26,14 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
static const float fingerVectorRadix = 4; // bits of precision when converting from float<->fixed
|
||||
|
||||
QNetworkAccessManager* AvatarData::networkAccessManager = NULL;
|
||||
|
||||
AvatarData::AvatarData() :
|
||||
NodeData(),
|
||||
_handPosition(0,0,0),
|
||||
_bodyYaw(-90.0),
|
||||
_bodyPitch(0.0),
|
||||
_bodyRoll(0.0),
|
||||
_bodyYaw(-90.f),
|
||||
_bodyPitch(0.0f),
|
||||
_bodyRoll(0.0f),
|
||||
_targetScale(1.0f),
|
||||
_handState(0),
|
||||
_keyState(NO_KEY_DOWN),
|
||||
|
@ -510,7 +508,7 @@ void AvatarData::setClampedTargetScale(float targetScale) {
|
|||
}
|
||||
|
||||
void AvatarData::setOrientation(const glm::quat& orientation) {
|
||||
glm::vec3 eulerAngles = safeEulerAngles(orientation);
|
||||
glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation));
|
||||
_bodyPitch = eulerAngles.x;
|
||||
_bodyYaw = eulerAngles.y;
|
||||
_bodyRoll = eulerAngles.z;
|
||||
|
|
|
@ -108,7 +108,7 @@ public:
|
|||
QByteArray toByteArray();
|
||||
int parseData(const QByteArray& packet);
|
||||
|
||||
// Body Rotation
|
||||
// Body Rotation (degrees)
|
||||
float getBodyYaw() const { return _bodyYaw; }
|
||||
void setBodyYaw(float bodyYaw) { _bodyYaw = bodyYaw; }
|
||||
float getBodyPitch() const { return _bodyPitch; }
|
||||
|
@ -122,7 +122,7 @@ public:
|
|||
glm::quat getHeadOrientation() const { return _headData->getOrientation(); }
|
||||
void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); }
|
||||
|
||||
// access to Head().set/getMousePitch
|
||||
// access to Head().set/getMousePitch (degrees)
|
||||
float getHeadPitch() const { return _headData->getPitch(); }
|
||||
void setHeadPitch(float value) { _headData->setPitch(value); };
|
||||
|
||||
|
@ -217,9 +217,9 @@ protected:
|
|||
glm::vec3 _handPosition;
|
||||
|
||||
// Body rotation
|
||||
float _bodyYaw;
|
||||
float _bodyPitch;
|
||||
float _bodyRoll;
|
||||
float _bodyYaw; // degrees
|
||||
float _bodyPitch; // degrees
|
||||
float _bodyRoll; // degrees
|
||||
|
||||
// Body scale
|
||||
float _targetScale;
|
||||
|
|
|
@ -17,9 +17,9 @@ HeadData::HeadData(AvatarData* owningAvatar) :
|
|||
_yaw(0.0f),
|
||||
_pitch(0.0f),
|
||||
_roll(0.0f),
|
||||
_lookAtPosition(0.0f, 0.0f, 0.0f),
|
||||
_leanSideways(0.0f),
|
||||
_leanForward(0.0f),
|
||||
_lookAtPosition(0.0f, 0.0f, 0.0f),
|
||||
_audioLoudness(0.0f),
|
||||
_isFaceshiftConnected(false),
|
||||
_leftEyeBlink(0.0f),
|
||||
|
@ -39,12 +39,11 @@ void HeadData::setOrientation(const glm::quat& orientation) {
|
|||
// rotate body about vertical axis
|
||||
glm::quat bodyOrientation = _owningAvatar->getOrientation();
|
||||
glm::vec3 newFront = glm::inverse(bodyOrientation) * (orientation * IDENTITY_FRONT);
|
||||
bodyOrientation = bodyOrientation * glm::angleAxis(glm::degrees(atan2f(-newFront.x, -newFront.z)),
|
||||
glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
bodyOrientation = bodyOrientation * glm::angleAxis(atan2f(-newFront.x, -newFront.z), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
_owningAvatar->setOrientation(bodyOrientation);
|
||||
|
||||
// the rest goes to the head
|
||||
glm::vec3 eulers = safeEulerAngles(glm::inverse(bodyOrientation) * orientation);
|
||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(glm::inverse(bodyOrientation) * orientation));
|
||||
_pitch = eulers.x;
|
||||
_yaw = eulers.y;
|
||||
_roll = eulers.z;
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
const float MIN_HEAD_YAW = -110;
|
||||
const float MAX_HEAD_YAW = 110;
|
||||
const float MIN_HEAD_PITCH = -60;
|
||||
const float MAX_HEAD_PITCH = 60;
|
||||
const float MIN_HEAD_ROLL = -50;
|
||||
const float MAX_HEAD_ROLL = 50;
|
||||
// degrees
|
||||
const float MIN_HEAD_YAW = -110.f;
|
||||
const float MAX_HEAD_YAW = 110.f;
|
||||
const float MIN_HEAD_PITCH = -60.f;
|
||||
const float MAX_HEAD_PITCH = 60.f;
|
||||
const float MIN_HEAD_ROLL = -50.f;
|
||||
const float MAX_HEAD_ROLL = 50.f;
|
||||
|
||||
class AvatarData;
|
||||
|
||||
|
@ -29,21 +30,17 @@ public:
|
|||
HeadData(AvatarData* owningAvatar);
|
||||
virtual ~HeadData() { };
|
||||
|
||||
// degrees
|
||||
float getLeanSideways() const { return _leanSideways; }
|
||||
void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; }
|
||||
|
||||
float getLeanForward() const { return _leanForward; }
|
||||
void setLeanForward(float leanForward) { _leanForward = leanForward; }
|
||||
|
||||
float getYaw() const { return _yaw; }
|
||||
void setYaw(float yaw) { _yaw = glm::clamp(yaw, MIN_HEAD_YAW, MAX_HEAD_YAW); }
|
||||
|
||||
float getPitch() const { return _pitch; }
|
||||
void setPitch(float pitch) { _pitch = glm::clamp(pitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); }
|
||||
|
||||
float getRoll() const { return _roll; }
|
||||
void setRoll(float roll) { _roll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); }
|
||||
|
||||
virtual float getTweakedYaw() const { return _yaw; }
|
||||
virtual float getTweakedPitch() const { return _pitch; }
|
||||
virtual float getTweakedRoll() const { return _roll; }
|
||||
|
@ -62,6 +59,7 @@ public:
|
|||
float getPupilDilation() const { return _pupilDilation; }
|
||||
void setPupilDilation(float pupilDilation) { _pupilDilation = pupilDilation; }
|
||||
|
||||
// degrees
|
||||
void addYaw(float yaw);
|
||||
void addPitch(float pitch);
|
||||
void addRoll(float roll);
|
||||
|
@ -73,12 +71,14 @@ public:
|
|||
friend class AvatarData;
|
||||
|
||||
protected:
|
||||
// degrees
|
||||
float _yaw;
|
||||
float _pitch;
|
||||
float _roll;
|
||||
glm::vec3 _lookAtPosition;
|
||||
float _leanSideways;
|
||||
float _leanForward;
|
||||
|
||||
glm::vec3 _lookAtPosition;
|
||||
float _audioLoudness;
|
||||
bool _isFaceshiftConnected;
|
||||
float _leftEyeBlink;
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
#include "MetavoxelData.h"
|
||||
|
||||
REGISTER_META_OBJECT(QRgbAttribute)
|
||||
REGISTER_META_OBJECT(PackedNormalAttribute)
|
||||
REGISTER_META_OBJECT(SharedObjectAttribute)
|
||||
REGISTER_META_OBJECT(SharedObjectSetAttribute)
|
||||
REGISTER_META_OBJECT(SpannerSetAttribute)
|
||||
|
||||
AttributeRegistry* AttributeRegistry::getInstance() {
|
||||
static AttributeRegistry registry;
|
||||
|
@ -23,9 +25,13 @@ AttributeRegistry* AttributeRegistry::getInstance() {
|
|||
AttributeRegistry::AttributeRegistry() :
|
||||
_guideAttribute(registerAttribute(new SharedObjectAttribute("guide", &MetavoxelGuide::staticMetaObject,
|
||||
SharedObjectPointer(new DefaultMetavoxelGuide())))),
|
||||
_spannersAttribute(registerAttribute(new SharedObjectSetAttribute("spanners", &Spanner::staticMetaObject))),
|
||||
_spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))),
|
||||
_colorAttribute(registerAttribute(new QRgbAttribute("color"))),
|
||||
_normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) {
|
||||
_normalAttribute(registerAttribute(new PackedNormalAttribute("normal", qRgb(0, 127, 0)))) {
|
||||
|
||||
// our baseline LOD threshold is for voxels; spanners are a different story
|
||||
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 4.0f;
|
||||
_spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER);
|
||||
}
|
||||
|
||||
static QScriptValue qDebugFunction(QScriptContext* context, QScriptEngine* engine) {
|
||||
|
@ -48,6 +54,9 @@ void AttributeRegistry::configureScriptEngine(QScriptEngine* engine) {
|
|||
}
|
||||
|
||||
AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) {
|
||||
if (!attribute) {
|
||||
return attribute;
|
||||
}
|
||||
AttributePointer& pointer = _attributes[attribute->getName()];
|
||||
if (!pointer) {
|
||||
pointer = attribute;
|
||||
|
@ -138,13 +147,38 @@ OwnedAttributeValue& OwnedAttributeValue::operator=(const OwnedAttributeValue& o
|
|||
return *this;
|
||||
}
|
||||
|
||||
Attribute::Attribute(const QString& name) {
|
||||
Attribute::Attribute(const QString& name) :
|
||||
_lodThresholdMultiplier(1.0f) {
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
Attribute::~Attribute() {
|
||||
}
|
||||
|
||||
void Attribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state) {
|
||||
data.createRoot(state.attribute)->read(state);
|
||||
}
|
||||
|
||||
void Attribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) {
|
||||
root.write(state);
|
||||
}
|
||||
|
||||
void Attribute::readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) {
|
||||
data.createRoot(state.attribute)->readDelta(reference, state);
|
||||
}
|
||||
|
||||
void Attribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) {
|
||||
root.writeDelta(reference, state);
|
||||
}
|
||||
|
||||
void Attribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) {
|
||||
data.getRoot(state.attribute)->readSubdivision(state);
|
||||
}
|
||||
|
||||
void Attribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) {
|
||||
root.writeSubdivision(state);
|
||||
}
|
||||
|
||||
QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) :
|
||||
InlineAttribute<QRgb>(name, defaultValue) {
|
||||
}
|
||||
|
@ -189,6 +223,39 @@ QWidget* QRgbAttribute::createEditor(QWidget* parent) const {
|
|||
return editor;
|
||||
}
|
||||
|
||||
PackedNormalAttribute::PackedNormalAttribute(const QString& name, QRgb defaultValue) :
|
||||
QRgbAttribute(name, defaultValue) {
|
||||
}
|
||||
|
||||
bool PackedNormalAttribute::merge(void*& parent, void* children[]) const {
|
||||
QRgb firstValue = decodeInline<QRgb>(children[0]);
|
||||
int totalRed = (char)qRed(firstValue);
|
||||
int totalGreen = (char)qGreen(firstValue);
|
||||
int totalBlue = (char)qBlue(firstValue);
|
||||
bool allChildrenEqual = true;
|
||||
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
|
||||
QRgb value = decodeInline<QRgb>(children[i]);
|
||||
totalRed += (char)qRed(value);
|
||||
totalGreen += (char)qGreen(value);
|
||||
totalBlue += (char)qBlue(value);
|
||||
allChildrenEqual &= (firstValue == value);
|
||||
}
|
||||
parent = encodeInline(packNormal(glm::normalize(glm::vec3(totalRed, totalGreen, totalBlue))));
|
||||
return allChildrenEqual;
|
||||
}
|
||||
|
||||
const float CHAR_SCALE = 127.0f;
|
||||
const float INVERSE_CHAR_SCALE = 1.0f / CHAR_SCALE;
|
||||
|
||||
QRgb packNormal(const glm::vec3& normal) {
|
||||
return qRgb((char)(normal.x * CHAR_SCALE), (char)(normal.y * CHAR_SCALE), (char)(normal.z * CHAR_SCALE));
|
||||
}
|
||||
|
||||
glm::vec3 unpackNormal(QRgb value) {
|
||||
return glm::vec3((char)qRed(value) * INVERSE_CHAR_SCALE, (char)qGreen(value) * INVERSE_CHAR_SCALE,
|
||||
(char)qBlue(value) * INVERSE_CHAR_SCALE);
|
||||
}
|
||||
|
||||
SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject,
|
||||
const SharedObjectPointer& defaultValue) :
|
||||
InlineAttribute<SharedObjectPointer>(name, defaultValue),
|
||||
|
@ -255,3 +322,61 @@ bool SharedObjectSetAttribute::merge(void*& parent, void* children[]) const {
|
|||
QWidget* SharedObjectSetAttribute::createEditor(QWidget* parent) const {
|
||||
return new SharedObjectEditor(_metaObject, parent);
|
||||
}
|
||||
|
||||
SpannerSetAttribute::SpannerSetAttribute(const QString& name, const QMetaObject* metaObject) :
|
||||
SharedObjectSetAttribute(name, metaObject) {
|
||||
}
|
||||
|
||||
void SpannerSetAttribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state) {
|
||||
forever {
|
||||
SharedObjectPointer object;
|
||||
state.stream >> object;
|
||||
if (!object) {
|
||||
break;
|
||||
}
|
||||
data.insert(state.attribute, object);
|
||||
}
|
||||
}
|
||||
|
||||
void SpannerSetAttribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) {
|
||||
Spanner::incrementVisit();
|
||||
root.writeSpanners(state);
|
||||
state.stream << SharedObjectPointer();
|
||||
}
|
||||
|
||||
void SpannerSetAttribute::readMetavoxelDelta(MetavoxelData& data,
|
||||
const MetavoxelNode& reference, MetavoxelStreamState& state) {
|
||||
forever {
|
||||
SharedObjectPointer object;
|
||||
state.stream >> object;
|
||||
if (!object) {
|
||||
break;
|
||||
}
|
||||
data.toggle(state.attribute, object);
|
||||
}
|
||||
}
|
||||
|
||||
void SpannerSetAttribute::writeMetavoxelDelta(const MetavoxelNode& root,
|
||||
const MetavoxelNode& reference, MetavoxelStreamState& state) {
|
||||
Spanner::incrementVisit();
|
||||
root.writeSpannerDelta(reference, state);
|
||||
state.stream << SharedObjectPointer();
|
||||
}
|
||||
|
||||
void SpannerSetAttribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) {
|
||||
forever {
|
||||
SharedObjectPointer object;
|
||||
state.stream >> object;
|
||||
if (!object) {
|
||||
break;
|
||||
}
|
||||
data.insert(state.attribute, object);
|
||||
}
|
||||
}
|
||||
|
||||
void SpannerSetAttribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) {
|
||||
Spanner::incrementVisit();
|
||||
root.writeSpannerSubdivision(state);
|
||||
state.stream << SharedObjectPointer();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@ class QScriptEngine;
|
|||
class QScriptValue;
|
||||
|
||||
class Attribute;
|
||||
class MetavoxelData;
|
||||
class MetavoxelNode;
|
||||
class MetavoxelStreamState;
|
||||
|
||||
typedef SharedObjectPointerTemplate<Attribute> AttributePointer;
|
||||
|
||||
|
@ -150,6 +153,7 @@ public:
|
|||
/// Represents a registered attribute.
|
||||
class Attribute : public SharedObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float lodThresholdMultiplier MEMBER _lodThresholdMultiplier)
|
||||
|
||||
public:
|
||||
|
||||
|
@ -160,6 +164,9 @@ public:
|
|||
|
||||
Q_INVOKABLE QString getName() const { return objectName(); }
|
||||
|
||||
float getLODThresholdMultiplier() const { return _lodThresholdMultiplier; }
|
||||
void setLODThresholdMultiplier(float multiplier) { _lodThresholdMultiplier = multiplier; }
|
||||
|
||||
void* create() const { return create(getDefaultValue()); }
|
||||
virtual void* create(void* copy) const = 0;
|
||||
virtual void destroy(void* value) const = 0;
|
||||
|
@ -170,6 +177,15 @@ public:
|
|||
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { read(in, value, isLeaf); }
|
||||
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { write(out, value, isLeaf); }
|
||||
|
||||
virtual void readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state);
|
||||
virtual void writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state);
|
||||
|
||||
virtual void readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state);
|
||||
virtual void writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state);
|
||||
|
||||
virtual void readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state);
|
||||
virtual void writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state);
|
||||
|
||||
virtual bool equal(void* first, void* second) const = 0;
|
||||
|
||||
/// Merges the value of a parent and its children.
|
||||
|
@ -185,6 +201,10 @@ public:
|
|||
/// Creates a widget to use to edit values of this attribute, or returns NULL if the attribute isn't editable.
|
||||
/// The widget should have a single "user" property that will be used to get/set the value.
|
||||
virtual QWidget* createEditor(QWidget* parent = NULL) const { return NULL; }
|
||||
|
||||
private:
|
||||
|
||||
float _lodThresholdMultiplier;
|
||||
};
|
||||
|
||||
/// A simple attribute class that stores its values inline.
|
||||
|
@ -245,7 +265,7 @@ template<class T, int bits> inline bool SimpleInlineAttribute<T, bits>::merge(vo
|
|||
/// Provides appropriate averaging for RGBA values.
|
||||
class QRgbAttribute : public InlineAttribute<QRgb> {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int defaultValue MEMBER _defaultValue)
|
||||
Q_PROPERTY(uint defaultValue MEMBER _defaultValue)
|
||||
|
||||
public:
|
||||
|
||||
|
@ -260,6 +280,23 @@ public:
|
|||
virtual QWidget* createEditor(QWidget* parent = NULL) const;
|
||||
};
|
||||
|
||||
/// Provides appropriate averaging for packed normals.
|
||||
class PackedNormalAttribute : public QRgbAttribute {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE PackedNormalAttribute(const QString& name = QString(), QRgb defaultValue = QRgb());
|
||||
|
||||
virtual bool merge(void*& parent, void* children[]) const;
|
||||
};
|
||||
|
||||
/// Packs a normal into an RGB value.
|
||||
QRgb packNormal(const glm::vec3& normal);
|
||||
|
||||
/// Unpacks a normal from an RGB value.
|
||||
glm::vec3 unpackNormal(QRgb value);
|
||||
|
||||
/// An attribute that takes the form of QObjects of a given meta-type (a subclass of SharedObject).
|
||||
class SharedObjectAttribute : public InlineAttribute<SharedObjectPointer> {
|
||||
Q_OBJECT
|
||||
|
@ -309,4 +346,23 @@ private:
|
|||
const QMetaObject* _metaObject;
|
||||
};
|
||||
|
||||
/// An attribute that takes the form of a set of spanners.
|
||||
class SpannerSetAttribute : public SharedObjectSetAttribute {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE SpannerSetAttribute(const QString& name = QString(),
|
||||
const QMetaObject* metaObject = &SharedObject::staticMetaObject);
|
||||
|
||||
virtual void readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state);
|
||||
virtual void writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state);
|
||||
|
||||
virtual void readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state);
|
||||
virtual void writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state);
|
||||
|
||||
virtual void readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state);
|
||||
virtual void writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state);
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__AttributeRegistry__) */
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(bool)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(int)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(uint)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(float)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(QByteArray)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(QColor)
|
||||
|
@ -167,15 +168,19 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) {
|
|||
_scriptStringStreamer.persistTransientOffsets(mappings.scriptStringOffsets);
|
||||
_sharedObjectStreamer.persistTransientOffsets(mappings.sharedObjectOffsets);
|
||||
|
||||
// find out when shared objects' reference counts drop to one in order to clear their mappings
|
||||
// find out when shared objects are deleted in order to clear their mappings
|
||||
for (QHash<SharedObjectPointer, int>::const_iterator it = mappings.sharedObjectOffsets.constBegin();
|
||||
it != mappings.sharedObjectOffsets.constEnd(); it++) {
|
||||
if (it.key()) {
|
||||
connect(it.key().data(), SIGNAL(referenceCountDroppedToOne()), SLOT(clearSharedObject()));
|
||||
connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bitstream::persistAndResetWriteMappings() {
|
||||
persistWriteMappings(getAndResetWriteMappings());
|
||||
}
|
||||
|
||||
Bitstream::ReadMappings Bitstream::getAndResetReadMappings() {
|
||||
ReadMappings mappings = { _metaObjectStreamer.getAndResetTransientValues(),
|
||||
_typeStreamerStreamer.getAndResetTransientValues(),
|
||||
|
@ -193,6 +198,17 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) {
|
|||
_sharedObjectStreamer.persistTransientValues(mappings.sharedObjectValues);
|
||||
}
|
||||
|
||||
void Bitstream::persistAndResetReadMappings() {
|
||||
persistReadMappings(getAndResetReadMappings());
|
||||
}
|
||||
|
||||
void Bitstream::clearSharedObject(int id) {
|
||||
SharedObjectPointer object = _sharedObjectStreamer.takePersistentValue(id);
|
||||
if (object) {
|
||||
_weakSharedObjectHash.remove(object->getRemoteID());
|
||||
}
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(bool value) {
|
||||
if (value) {
|
||||
_byte |= (1 << _position);
|
||||
|
@ -223,6 +239,17 @@ Bitstream& Bitstream::operator>>(int& value) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(uint value) {
|
||||
return write(&value, 32);
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(uint& value) {
|
||||
quint32 sizedValue;
|
||||
read(&sizedValue, 32);
|
||||
value = sizedValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(float value) {
|
||||
return write(&value, 32);
|
||||
}
|
||||
|
@ -479,7 +506,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
|
|||
object = SharedObjectPointer();
|
||||
return *this;
|
||||
}
|
||||
QPointer<SharedObject>& pointer = _transientSharedObjects[id];
|
||||
QPointer<SharedObject>& pointer = _weakSharedObjectHash[id];
|
||||
if (pointer) {
|
||||
const QMetaObject* metaObject;
|
||||
_metaObjectStreamer >> metaObject;
|
||||
|
@ -492,15 +519,17 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
|
|||
QObject* rawObject;
|
||||
*this >> rawObject;
|
||||
pointer = static_cast<SharedObject*>(rawObject);
|
||||
pointer->setRemoteID(id);
|
||||
}
|
||||
object = static_cast<SharedObject*>(pointer.data());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Bitstream::clearSharedObject() {
|
||||
SharedObjectPointer object(static_cast<SharedObject*>(sender()));
|
||||
object->disconnect(this);
|
||||
emit sharedObjectCleared(_sharedObjectStreamer.takePersistentID(object));
|
||||
void Bitstream::clearSharedObject(QObject* object) {
|
||||
int id = _sharedObjectStreamer.takePersistentID(static_cast<SharedObject*>(object));
|
||||
if (id != 0) {
|
||||
emit sharedObjectCleared(id);
|
||||
}
|
||||
}
|
||||
|
||||
void Bitstream::readProperties(QObject* object) {
|
||||
|
|
|
@ -55,7 +55,7 @@ private:
|
|||
|
||||
/// Provides a means to stream repeated values efficiently. The value is first streamed along with a unique ID. When
|
||||
/// subsequently streamed, only the ID is sent.
|
||||
template<class T> class RepeatedValueStreamer {
|
||||
template<class T, class P = T> class RepeatedValueStreamer {
|
||||
public:
|
||||
|
||||
RepeatedValueStreamer(Bitstream& stream) : _stream(stream), _idStreamer(stream),
|
||||
|
@ -69,9 +69,9 @@ public:
|
|||
|
||||
void persistTransientValues(const QHash<int, T>& transientValues);
|
||||
|
||||
int takePersistentID(T value) { return _persistentIDs.take(value); }
|
||||
int takePersistentID(P value) { return _persistentIDs.take(value); }
|
||||
|
||||
void removePersistentValue(int id) { _persistentValues.remove(id); }
|
||||
T takePersistentValue(int id) { T value = _persistentValues.take(id); _persistentIDs.remove(value); return value; }
|
||||
|
||||
RepeatedValueStreamer& operator<<(T value);
|
||||
RepeatedValueStreamer& operator>>(T& value);
|
||||
|
@ -82,13 +82,13 @@ private:
|
|||
IDStreamer _idStreamer;
|
||||
int _lastPersistentID;
|
||||
int _lastTransientOffset;
|
||||
QHash<T, int> _persistentIDs;
|
||||
QHash<P, int> _persistentIDs;
|
||||
QHash<T, int> _transientOffsets;
|
||||
QHash<int, T> _persistentValues;
|
||||
QHash<int, T> _transientValues;
|
||||
};
|
||||
|
||||
template<class T> inline QHash<T, int> RepeatedValueStreamer<T>::getAndResetTransientOffsets() {
|
||||
template<class T, class P> inline QHash<T, int> RepeatedValueStreamer<T, P>::getAndResetTransientOffsets() {
|
||||
QHash<T, int> transientOffsets;
|
||||
_transientOffsets.swap(transientOffsets);
|
||||
_lastTransientOffset = 0;
|
||||
|
@ -96,7 +96,8 @@ template<class T> inline QHash<T, int> RepeatedValueStreamer<T>::getAndResetTran
|
|||
return transientOffsets;
|
||||
}
|
||||
|
||||
template<class T> inline void RepeatedValueStreamer<T>::persistTransientOffsets(const QHash<T, int>& transientOffsets) {
|
||||
template<class T, class P> inline void RepeatedValueStreamer<T, P>::persistTransientOffsets(
|
||||
const QHash<T, int>& transientOffsets) {
|
||||
int oldLastPersistentID = _lastPersistentID;
|
||||
for (typename QHash<T, int>::const_iterator it = transientOffsets.constBegin(); it != transientOffsets.constEnd(); it++) {
|
||||
int& id = _persistentIDs[it.key()];
|
||||
|
@ -108,14 +109,15 @@ template<class T> inline void RepeatedValueStreamer<T>::persistTransientOffsets(
|
|||
_idStreamer.setBitsFromValue(_lastPersistentID);
|
||||
}
|
||||
|
||||
template<class T> inline QHash<int, T> RepeatedValueStreamer<T>::getAndResetTransientValues() {
|
||||
template<class T, class P> inline QHash<int, T> RepeatedValueStreamer<T, P>::getAndResetTransientValues() {
|
||||
QHash<int, T> transientValues;
|
||||
_transientValues.swap(transientValues);
|
||||
_idStreamer.setBitsFromValue(_lastPersistentID);
|
||||
return transientValues;
|
||||
}
|
||||
|
||||
template<class T> inline void RepeatedValueStreamer<T>::persistTransientValues(const QHash<int, T>& transientValues) {
|
||||
template<class T, class P> inline void RepeatedValueStreamer<T, P>::persistTransientValues(
|
||||
const QHash<int, T>& transientValues) {
|
||||
int oldLastPersistentID = _lastPersistentID;
|
||||
for (typename QHash<int, T>::const_iterator it = transientValues.constBegin(); it != transientValues.constEnd(); it++) {
|
||||
int& id = _persistentIDs[it.value()];
|
||||
|
@ -128,7 +130,7 @@ template<class T> inline void RepeatedValueStreamer<T>::persistTransientValues(c
|
|||
_idStreamer.setBitsFromValue(_lastPersistentID);
|
||||
}
|
||||
|
||||
template<class T> inline RepeatedValueStreamer<T>& RepeatedValueStreamer<T>::operator<<(T value) {
|
||||
template<class T, class P> inline RepeatedValueStreamer<T, P>& RepeatedValueStreamer<T, P>::operator<<(T value) {
|
||||
int id = _persistentIDs.value(value);
|
||||
if (id == 0) {
|
||||
int& offset = _transientOffsets[value];
|
||||
|
@ -145,7 +147,7 @@ template<class T> inline RepeatedValueStreamer<T>& RepeatedValueStreamer<T>::ope
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<class T> inline RepeatedValueStreamer<T>& RepeatedValueStreamer<T>::operator>>(T& value) {
|
||||
template<class T, class P> inline RepeatedValueStreamer<T, P>& RepeatedValueStreamer<T, P>::operator>>(T& value) {
|
||||
int id;
|
||||
_idStreamer >> id;
|
||||
if (id <= _lastPersistentID) {
|
||||
|
@ -228,14 +230,23 @@ public:
|
|||
/// Persists a set of write mappings recorded earlier.
|
||||
void persistWriteMappings(const WriteMappings& mappings);
|
||||
|
||||
/// Immediately persists and resets the write mappings.
|
||||
void persistAndResetWriteMappings();
|
||||
|
||||
/// Returns the set of transient mappings gathered during reading and resets them.
|
||||
ReadMappings getAndResetReadMappings();
|
||||
|
||||
/// Persists a set of read mappings recorded earlier.
|
||||
void persistReadMappings(const ReadMappings& mappings);
|
||||
|
||||
/// Immediately persists and resets the read mappings.
|
||||
void persistAndResetReadMappings();
|
||||
|
||||
/// Returns a reference to the weak hash storing shared objects for this stream.
|
||||
const WeakSharedObjectHash& getWeakSharedObjectHash() const { return _weakSharedObjectHash; }
|
||||
|
||||
/// Removes a shared object from the read mappings.
|
||||
void clearSharedObject(int id) { _sharedObjectStreamer.removePersistentValue(id); }
|
||||
void clearSharedObject(int id);
|
||||
|
||||
Bitstream& operator<<(bool value);
|
||||
Bitstream& operator>>(bool& value);
|
||||
|
@ -243,6 +254,9 @@ public:
|
|||
Bitstream& operator<<(int value);
|
||||
Bitstream& operator>>(int& value);
|
||||
|
||||
Bitstream& operator<<(uint value);
|
||||
Bitstream& operator>>(uint& value);
|
||||
|
||||
Bitstream& operator<<(float value);
|
||||
Bitstream& operator>>(float& value);
|
||||
|
||||
|
@ -315,7 +329,7 @@ signals:
|
|||
|
||||
private slots:
|
||||
|
||||
void clearSharedObject();
|
||||
void clearSharedObject(QObject* object);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -329,9 +343,9 @@ private:
|
|||
RepeatedValueStreamer<const TypeStreamer*> _typeStreamerStreamer;
|
||||
RepeatedValueStreamer<AttributePointer> _attributeStreamer;
|
||||
RepeatedValueStreamer<QScriptString> _scriptStringStreamer;
|
||||
RepeatedValueStreamer<SharedObjectPointer> _sharedObjectStreamer;
|
||||
RepeatedValueStreamer<SharedObjectPointer, SharedObject*> _sharedObjectStreamer;
|
||||
|
||||
QHash<int, QPointer<SharedObject> > _transientSharedObjects;
|
||||
WeakSharedObjectHash _weakSharedObjectHash;
|
||||
|
||||
static QHash<QByteArray, const QMetaObject*>& getMetaObjects();
|
||||
static QMultiHash<const QMetaObject*, const QMetaObject*>& getMetaObjectSubClasses();
|
||||
|
|
|
@ -587,6 +587,7 @@ void ReliableChannel::sendMessage(const QVariant& message) {
|
|||
_dataStream << (quint32)0;
|
||||
_bitstream << message;
|
||||
_bitstream.flush();
|
||||
_bitstream.persistAndResetWriteMappings();
|
||||
|
||||
quint32 length = _buffer.pos() - placeholder;
|
||||
_buffer.writeBytes(placeholder, sizeof(quint32), (const char*)&length);
|
||||
|
@ -745,6 +746,7 @@ void ReliableChannel::readData(QDataStream& in) {
|
|||
QVariant message;
|
||||
_bitstream >> message;
|
||||
_bitstream.reset();
|
||||
_bitstream.persistAndResetReadMappings();
|
||||
emit receivedMessage(message);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ public:
|
|||
|
||||
DatagramSequencer(const QByteArray& datagramHeader = QByteArray(), QObject* parent = NULL);
|
||||
|
||||
/// Returns a reference to the weak hash mapping remote ids to shared objects.
|
||||
const WeakSharedObjectHash& getWeakSharedObjectHash() const { return _inputStream.getWeakSharedObjectHash(); }
|
||||
|
||||
/// Returns the packet number of the last packet sent.
|
||||
int getOutgoingPacketNumber() const { return _outgoingPacketNumber; }
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -31,6 +31,26 @@ class NetworkValue;
|
|||
class Spanner;
|
||||
class SpannerRenderer;
|
||||
|
||||
/// Determines whether to subdivide each node when traversing.
|
||||
class MetavoxelLOD {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
STREAM glm::vec3 position;
|
||||
STREAM float threshold;
|
||||
|
||||
MetavoxelLOD(const glm::vec3& position = glm::vec3(), float threshold = 0.0f);
|
||||
|
||||
bool isValid() const { return threshold > 0.0f; }
|
||||
|
||||
bool shouldSubdivide(const glm::vec3& minimum, float size, float multiplier = 1.0f) const;
|
||||
|
||||
/// Checks whether the node or any of the nodes underneath it have had subdivision enabled as compared to the reference.
|
||||
bool becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference, float multiplier = 1.0f) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(MetavoxelLOD)
|
||||
|
||||
/// The base metavoxel representation shared between server and client.
|
||||
class MetavoxelData {
|
||||
public:
|
||||
|
@ -43,25 +63,40 @@ public:
|
|||
|
||||
float getSize() const { return _size; }
|
||||
|
||||
glm::vec3 getMinimum() const { return glm::vec3(_size, _size, _size) * -0.5f; }
|
||||
|
||||
Box getBounds() const;
|
||||
|
||||
/// Applies the specified visitor to the contained voxels.
|
||||
void guide(MetavoxelVisitor& visitor);
|
||||
|
||||
void insert(const AttributePointer& attribute, const SharedObjectPointer& object);
|
||||
void insert(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object);
|
||||
|
||||
void remove(const AttributePointer& attribute, const SharedObjectPointer& object);
|
||||
void remove(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object);
|
||||
|
||||
void toggle(const AttributePointer& attribute, const SharedObjectPointer& object);
|
||||
void toggle(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object);
|
||||
|
||||
void clear(const AttributePointer& attribute);
|
||||
|
||||
/// Convenience function that finds the first spanner intersecting the provided ray.
|
||||
SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
const AttributePointer& attribute, float& distance, const MetavoxelLOD& lod = MetavoxelLOD());
|
||||
|
||||
/// Expands the tree, increasing its capacity in all dimensions.
|
||||
void expand();
|
||||
|
||||
void read(Bitstream& in);
|
||||
void write(Bitstream& out) const;
|
||||
void read(Bitstream& in, const MetavoxelLOD& lod = MetavoxelLOD());
|
||||
void write(Bitstream& out, const MetavoxelLOD& lod = MetavoxelLOD()) const;
|
||||
|
||||
void readDelta(const MetavoxelData& reference, Bitstream& in);
|
||||
void writeDelta(const MetavoxelData& reference, Bitstream& out) const;
|
||||
void readDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, Bitstream& in, const MetavoxelLOD& lod);
|
||||
void writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD,
|
||||
Bitstream& out, const MetavoxelLOD& lod) const;
|
||||
|
||||
MetavoxelNode* getRoot(const AttributePointer& attribute) const { return _roots.value(attribute); }
|
||||
MetavoxelNode* createRoot(const AttributePointer& attribute);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -74,6 +109,23 @@ private:
|
|||
QHash<AttributePointer, MetavoxelNode*> _roots;
|
||||
};
|
||||
|
||||
/// Holds the state used in streaming metavoxel data.
|
||||
class MetavoxelStreamState {
|
||||
public:
|
||||
glm::vec3 minimum;
|
||||
float size;
|
||||
const AttributePointer& attribute;
|
||||
Bitstream& stream;
|
||||
const MetavoxelLOD& lod;
|
||||
const MetavoxelLOD& referenceLOD;
|
||||
|
||||
bool shouldSubdivide() const;
|
||||
bool shouldSubdivideReference() const;
|
||||
bool becameSubdivided() const;
|
||||
|
||||
void setMinimum(const glm::vec3& lastMinimum, int index);
|
||||
};
|
||||
|
||||
/// A single node within a metavoxel layer.
|
||||
class MetavoxelNode {
|
||||
public:
|
||||
|
@ -95,11 +147,18 @@ public:
|
|||
|
||||
bool isLeaf() const;
|
||||
|
||||
void read(const AttributePointer& attribute, Bitstream& in);
|
||||
void write(const AttributePointer& attribute, Bitstream& out) const;
|
||||
void read(MetavoxelStreamState& state);
|
||||
void write(MetavoxelStreamState& state) const;
|
||||
|
||||
void readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in);
|
||||
void writeDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& out) const;
|
||||
void readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state);
|
||||
void writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const;
|
||||
|
||||
void readSubdivision(MetavoxelStreamState& state);
|
||||
void writeSubdivision(MetavoxelStreamState& state) const;
|
||||
|
||||
void writeSpanners(MetavoxelStreamState& state) const;
|
||||
void writeSpannerDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const;
|
||||
void writeSpannerSubdivision(MetavoxelStreamState& state) const;
|
||||
|
||||
/// Increments the node's reference count.
|
||||
void incrementReferenceCount() { _referenceCount++; }
|
||||
|
@ -133,14 +192,31 @@ public:
|
|||
bool isLeaf;
|
||||
|
||||
Box getBounds() const { return Box(minimum, minimum + glm::vec3(size, size, size)); }
|
||||
glm::vec3 getCenter() const { return minimum + glm::vec3(size, size, size) * 0.5f; }
|
||||
};
|
||||
|
||||
/// Interface for visitors to metavoxels.
|
||||
/// Base class for visitors to metavoxels.
|
||||
class MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
/// Encodes a visitation order sequence for the children of a metavoxel.
|
||||
static int encodeOrder(int first, int second, int third, int fourth, int fifth, int sixth, int seventh, int eighth);
|
||||
|
||||
/// Encodes a visitation order sequence that visits each child as sorted along the specified direction.
|
||||
static int encodeOrder(const glm::vec3& direction);
|
||||
|
||||
/// The default visitation order.
|
||||
static const int DEFAULT_ORDER;
|
||||
|
||||
/// A special "order" that instructs the guide to stop recursion.
|
||||
static const int STOP_RECURSION;
|
||||
|
||||
/// A special "order" that short-circuits the tour.
|
||||
static const int SHORT_CIRCUIT;
|
||||
|
||||
MetavoxelVisitor(const QVector<AttributePointer>& inputs,
|
||||
const QVector<AttributePointer>& outputs = QVector<AttributePointer>());
|
||||
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
|
||||
const MetavoxelLOD& lod = MetavoxelLOD());
|
||||
virtual ~MetavoxelVisitor();
|
||||
|
||||
/// Returns a reference to the list of input attributes desired.
|
||||
|
@ -149,41 +225,93 @@ public:
|
|||
/// Returns a reference to the list of output attributes provided.
|
||||
const QVector<AttributePointer>& getOutputs() const { return _outputs; }
|
||||
|
||||
/// Returns a reference to the level of detail that will determine subdivision levels.
|
||||
const MetavoxelLOD& getLOD() const { return _lod; }
|
||||
|
||||
void setLOD(const MetavoxelLOD& lod) { _lod = lod; }
|
||||
|
||||
float getMinimumLODThresholdMultiplier() const { return _minimumLODThresholdMultiplier; }
|
||||
|
||||
/// Prepares for a new tour of the metavoxel data.
|
||||
virtual void prepare();
|
||||
|
||||
/// Visits a metavoxel.
|
||||
/// \param info the metavoxel data
|
||||
/// \return if true, continue descending; if false, stop
|
||||
virtual bool visit(MetavoxelInfo& info) = 0;
|
||||
/// \return the encoded order in which to traverse the children, zero to stop recursion, or -1 to short-circuit the tour
|
||||
virtual int visit(MetavoxelInfo& info) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
QVector<AttributePointer> _inputs;
|
||||
QVector<AttributePointer> _outputs;
|
||||
MetavoxelLOD _lod;
|
||||
float _minimumLODThresholdMultiplier;
|
||||
};
|
||||
|
||||
typedef QSharedPointer<MetavoxelVisitor> MetavoxelVisitorPointer;
|
||||
|
||||
/// Interface for visitors to spanners.
|
||||
/// Base class for visitors to spanners.
|
||||
class SpannerVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
SpannerVisitor(const QVector<AttributePointer>& spannerInputs,
|
||||
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
|
||||
const QVector<AttributePointer>& outputs = QVector<AttributePointer>());
|
||||
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
|
||||
const MetavoxelLOD& lod = MetavoxelLOD());
|
||||
|
||||
/// Visits a spanner.
|
||||
virtual void visit(Spanner* spanner) = 0;
|
||||
/// \return true to continue, false to short-circuit the tour
|
||||
virtual bool visit(Spanner* spanner) = 0;
|
||||
|
||||
virtual void prepare();
|
||||
virtual bool visit(MetavoxelInfo& info);
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
protected:
|
||||
|
||||
int _spannerInputCount;
|
||||
};
|
||||
|
||||
/// Base class for ray intersection visitors.
|
||||
class RayIntersectionVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
RayIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
|
||||
const QVector<AttributePointer>& inputs,
|
||||
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
|
||||
const MetavoxelLOD& lod = MetavoxelLOD());
|
||||
|
||||
/// Visits a metavoxel that the ray intersects.
|
||||
virtual int visit(MetavoxelInfo& info, float distance) = 0;
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
protected:
|
||||
|
||||
glm::vec3 _origin;
|
||||
glm::vec3 _direction;
|
||||
int _order;
|
||||
};
|
||||
|
||||
/// Base class for ray intersection spanner visitors.
|
||||
class RaySpannerIntersectionVisitor : public RayIntersectionVisitor {
|
||||
public:
|
||||
|
||||
RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
|
||||
const QVector<AttributePointer>& spannerInputs,
|
||||
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
|
||||
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
|
||||
const MetavoxelLOD& lod = MetavoxelLOD());
|
||||
|
||||
/// Visits a spanner that the ray intersects.
|
||||
/// \return true to continue, false to short-circuit the tour
|
||||
virtual bool visitSpanner(Spanner* spanner, float distance) = 0;
|
||||
|
||||
virtual void prepare();
|
||||
virtual int visit(MetavoxelInfo& info, float distance);
|
||||
|
||||
protected:
|
||||
|
||||
int _spannerInputCount;
|
||||
};
|
||||
|
||||
/// Interface for objects that guide metavoxel visitors.
|
||||
class MetavoxelGuide : public SharedObject {
|
||||
Q_OBJECT
|
||||
|
@ -191,7 +319,8 @@ class MetavoxelGuide : public SharedObject {
|
|||
public:
|
||||
|
||||
/// Guides the specified visitor to the contained voxels.
|
||||
virtual void guide(MetavoxelVisitation& visitation) = 0;
|
||||
/// \return true to keep going, false to short circuit the tour
|
||||
virtual bool guide(MetavoxelVisitation& visitation) = 0;
|
||||
};
|
||||
|
||||
/// Guides visitors through the explicit content of the system.
|
||||
|
@ -202,7 +331,7 @@ public:
|
|||
|
||||
Q_INVOKABLE DefaultMetavoxelGuide();
|
||||
|
||||
virtual void guide(MetavoxelVisitation& visitation);
|
||||
virtual bool guide(MetavoxelVisitation& visitation);
|
||||
};
|
||||
|
||||
/// A temporary test guide that just makes the existing voxels throb with delight.
|
||||
|
@ -214,7 +343,7 @@ public:
|
|||
|
||||
Q_INVOKABLE ThrobbingMetavoxelGuide();
|
||||
|
||||
virtual void guide(MetavoxelVisitation& visitation);
|
||||
virtual bool guide(MetavoxelVisitation& visitation);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -230,7 +359,7 @@ public:
|
|||
|
||||
Q_INVOKABLE ScriptedMetavoxelGuide();
|
||||
|
||||
virtual void guide(MetavoxelVisitation& visitation);
|
||||
virtual bool guide(MetavoxelVisitation& visitation);
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -294,6 +423,13 @@ public:
|
|||
void setGranularity(float granularity) { _granularity = granularity; }
|
||||
float getGranularity() const { return _granularity; }
|
||||
|
||||
/// Returns a reference to the list of attributes associated with this spanner.
|
||||
virtual const QVector<AttributePointer>& getAttributes() const;
|
||||
|
||||
/// Sets the attribute values associated with this spanner in the supplied info.
|
||||
/// \return true to recurse, false to stop
|
||||
virtual bool getAttributeValues(MetavoxelInfo& info) const;
|
||||
|
||||
/// Checks whether we've visited this object on the current traversal. If we have, returns false.
|
||||
/// If we haven't, sets the last visit identifier and returns true.
|
||||
bool testAndSetVisited();
|
||||
|
@ -301,6 +437,9 @@ public:
|
|||
/// Returns a pointer to the renderer, creating it if necessary.
|
||||
SpannerRenderer* getRenderer();
|
||||
|
||||
/// Finds the intersection between the described ray and this spanner.
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
|
||||
signals:
|
||||
|
||||
void boundsWillChange();
|
||||
|
@ -308,6 +447,8 @@ signals:
|
|||
|
||||
protected:
|
||||
|
||||
SpannerRenderer* _renderer;
|
||||
|
||||
/// Returns the name of the class to instantiate in order to render this spanner.
|
||||
virtual QByteArray getRendererClassName() const;
|
||||
|
||||
|
@ -316,7 +457,6 @@ private:
|
|||
Box _bounds;
|
||||
float _granularity;
|
||||
int _lastVisit; ///< the identifier of the last visit
|
||||
SpannerRenderer* _renderer;
|
||||
|
||||
static int _visit; ///< the global visit counter
|
||||
};
|
||||
|
@ -332,6 +472,7 @@ public:
|
|||
virtual void init(Spanner* spanner);
|
||||
virtual void simulate(float deltaTime);
|
||||
virtual void render(float alpha);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
};
|
||||
|
||||
/// An object with a 3D transform.
|
||||
|
@ -363,10 +504,45 @@ signals:
|
|||
private:
|
||||
|
||||
glm::vec3 _translation;
|
||||
glm::vec3 _rotation;
|
||||
glm::vec3 _rotation; // Euler Angles in degrees
|
||||
float _scale;
|
||||
};
|
||||
|
||||
/// A sphere.
|
||||
class Sphere : public Transformable {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor color MEMBER _color WRITE setColor NOTIFY colorChanged)
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE Sphere();
|
||||
|
||||
void setColor(const QColor& color);
|
||||
const QColor& getColor() const { return _color; }
|
||||
|
||||
virtual const QVector<AttributePointer>& getAttributes() const;
|
||||
virtual bool getAttributeValues(MetavoxelInfo& info) const;
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
|
||||
signals:
|
||||
|
||||
void colorChanged(const QColor& color);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QByteArray getRendererClassName() const;
|
||||
|
||||
private slots:
|
||||
|
||||
void updateBounds();
|
||||
|
||||
private:
|
||||
|
||||
void getNormal(MetavoxelInfo& info) const;
|
||||
|
||||
QColor _color;
|
||||
};
|
||||
|
||||
/// A static 3D model loaded from the network.
|
||||
class StaticModel : public Transformable {
|
||||
Q_OBJECT
|
||||
|
@ -379,6 +555,8 @@ public:
|
|||
void setURL(const QUrl& url);
|
||||
const QUrl& getURL() const { return _url; }
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
|
||||
signals:
|
||||
|
||||
void urlChanged(const QUrl& url);
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "MetavoxelData.h"
|
||||
#include "MetavoxelMessages.h"
|
||||
|
||||
void MetavoxelEditMessage::apply(MetavoxelData& data) const {
|
||||
static_cast<const MetavoxelEdit*>(edit.data())->apply(data);
|
||||
void MetavoxelEditMessage::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
static_cast<const MetavoxelEdit*>(edit.data())->apply(data, objects);
|
||||
}
|
||||
|
||||
MetavoxelEdit::~MetavoxelEdit() {
|
||||
|
@ -25,7 +24,7 @@ public:
|
|||
|
||||
BoxSetEditVisitor(const BoxSetEdit& edit);
|
||||
|
||||
virtual bool visit(MetavoxelInfo& info);
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -37,29 +36,29 @@ BoxSetEditVisitor::BoxSetEditVisitor(const BoxSetEdit& edit) :
|
|||
_edit(edit) {
|
||||
}
|
||||
|
||||
bool BoxSetEditVisitor::visit(MetavoxelInfo& info) {
|
||||
int BoxSetEditVisitor::visit(MetavoxelInfo& info) {
|
||||
// find the intersection between volume and voxel
|
||||
glm::vec3 minimum = glm::max(info.minimum, _edit.region.minimum);
|
||||
glm::vec3 maximum = glm::min(info.minimum + glm::vec3(info.size, info.size, info.size), _edit.region.maximum);
|
||||
glm::vec3 size = maximum - minimum;
|
||||
if (size.x <= 0.0f || size.y <= 0.0f || size.z <= 0.0f) {
|
||||
return false; // disjoint
|
||||
return STOP_RECURSION; // disjoint
|
||||
}
|
||||
float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size);
|
||||
if (volume >= 1.0f) {
|
||||
info.outputValues[0] = _edit.value;
|
||||
return false; // entirely contained
|
||||
return STOP_RECURSION; // entirely contained
|
||||
}
|
||||
if (info.size <= _edit.granularity) {
|
||||
if (volume >= 0.5f) {
|
||||
info.outputValues[0] = _edit.value;
|
||||
}
|
||||
return false; // reached granularity limit; take best guess
|
||||
return STOP_RECURSION; // reached granularity limit; take best guess
|
||||
}
|
||||
return true; // subdivide
|
||||
return DEFAULT_ORDER; // subdivide
|
||||
}
|
||||
|
||||
void BoxSetEdit::apply(MetavoxelData& data) const {
|
||||
void BoxSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
// expand to fit the entire edit
|
||||
while (!data.getBounds().contains(region)) {
|
||||
data.expand();
|
||||
|
@ -78,7 +77,7 @@ public:
|
|||
|
||||
GlobalSetEditVisitor(const GlobalSetEdit& edit);
|
||||
|
||||
virtual bool visit(MetavoxelInfo& info);
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -90,12 +89,12 @@ GlobalSetEditVisitor::GlobalSetEditVisitor(const GlobalSetEdit& edit) :
|
|||
_edit(edit) {
|
||||
}
|
||||
|
||||
bool GlobalSetEditVisitor::visit(MetavoxelInfo& info) {
|
||||
int GlobalSetEditVisitor::visit(MetavoxelInfo& info) {
|
||||
info.outputValues[0] = _edit.value;
|
||||
return false; // entirely contained
|
||||
return STOP_RECURSION; // entirely contained
|
||||
}
|
||||
|
||||
void GlobalSetEdit::apply(MetavoxelData& data) const {
|
||||
void GlobalSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
GlobalSetEditVisitor visitor(*this);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
@ -105,9 +104,8 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh
|
|||
spanner(spanner) {
|
||||
}
|
||||
|
||||
void InsertSpannerEdit::apply(MetavoxelData& data) const {
|
||||
Spanner* spanner = static_cast<Spanner*>(this->spanner.data());
|
||||
data.insert(attribute, spanner->getBounds(), spanner->getGranularity(), this->spanner);
|
||||
void InsertSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
data.insert(attribute, spanner);
|
||||
}
|
||||
|
||||
RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) :
|
||||
|
@ -115,13 +113,56 @@ RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id)
|
|||
id(id) {
|
||||
}
|
||||
|
||||
void RemoveSpannerEdit::apply(MetavoxelData& data) const {
|
||||
void RemoveSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
SharedObject* object = objects.value(id);
|
||||
if (!object) {
|
||||
qDebug() << "Missing object to remove" << id;
|
||||
return;
|
||||
}
|
||||
data.remove(attribute, object);
|
||||
}
|
||||
|
||||
ClearSpannersEdit::ClearSpannersEdit(const AttributePointer& attribute) :
|
||||
attribute(attribute) {
|
||||
}
|
||||
|
||||
void ClearSpannersEdit::apply(MetavoxelData& data) const {
|
||||
void ClearSpannersEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
data.clear(attribute);
|
||||
}
|
||||
|
||||
class SetSpannerEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
SetSpannerEditVisitor(Spanner* spanner);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
Spanner* _spanner;
|
||||
};
|
||||
|
||||
SetSpannerEditVisitor::SetSpannerEditVisitor(Spanner* spanner) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>(), spanner->getAttributes()),
|
||||
_spanner(spanner) {
|
||||
}
|
||||
|
||||
int SetSpannerEditVisitor::visit(MetavoxelInfo& info) {
|
||||
return _spanner->getAttributeValues(info) ? DEFAULT_ORDER : STOP_RECURSION;
|
||||
}
|
||||
|
||||
SetSpannerEdit::SetSpannerEdit(const SharedObjectPointer& spanner) :
|
||||
spanner(spanner) {
|
||||
}
|
||||
|
||||
void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
Spanner* spanner = static_cast<Spanner*>(this->spanner.data());
|
||||
|
||||
// expand to fit the entire spanner
|
||||
while (!data.getBounds().contains(spanner->getBounds())) {
|
||||
data.expand();
|
||||
}
|
||||
|
||||
SetSpannerEditVisitor visitor(spanner);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
|
|
@ -9,10 +9,7 @@
|
|||
#ifndef __interface__MetavoxelMessages__
|
||||
#define __interface__MetavoxelMessages__
|
||||
|
||||
#include "AttributeRegistry.h"
|
||||
#include "MetavoxelUtil.h"
|
||||
|
||||
class MetavoxelData;
|
||||
#include "MetavoxelData.h"
|
||||
|
||||
/// Requests to close the session.
|
||||
class CloseSessionMessage {
|
||||
|
@ -49,7 +46,7 @@ class ClientStateMessage {
|
|||
|
||||
public:
|
||||
|
||||
STREAM glm::vec3 position;
|
||||
STREAM MetavoxelLOD lod;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(ClientStateMessage)
|
||||
|
@ -69,7 +66,7 @@ public:
|
|||
|
||||
STREAM QVariant edit;
|
||||
|
||||
void apply(MetavoxelData& data) const;
|
||||
void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(MetavoxelEditMessage)
|
||||
|
@ -80,7 +77,7 @@ public:
|
|||
|
||||
virtual ~MetavoxelEdit();
|
||||
|
||||
virtual void apply(MetavoxelData& data) const = 0;
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const = 0;
|
||||
};
|
||||
|
||||
/// An edit that sets the region within a box to a value.
|
||||
|
@ -96,7 +93,7 @@ public:
|
|||
BoxSetEdit(const Box& region = Box(), float granularity = 0.0f,
|
||||
const OwnedAttributeValue& value = OwnedAttributeValue());
|
||||
|
||||
virtual void apply(MetavoxelData& data) const;
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(BoxSetEdit)
|
||||
|
@ -111,7 +108,7 @@ public:
|
|||
|
||||
GlobalSetEdit(const OwnedAttributeValue& value = OwnedAttributeValue());
|
||||
|
||||
virtual void apply(MetavoxelData& data) const;
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(GlobalSetEdit)
|
||||
|
@ -128,7 +125,7 @@ public:
|
|||
InsertSpannerEdit(const AttributePointer& attribute = AttributePointer(),
|
||||
const SharedObjectPointer& spanner = SharedObjectPointer());
|
||||
|
||||
virtual void apply(MetavoxelData& data) const;
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(InsertSpannerEdit)
|
||||
|
@ -144,7 +141,7 @@ public:
|
|||
|
||||
RemoveSpannerEdit(const AttributePointer& attribute = AttributePointer(), int id = 0);
|
||||
|
||||
virtual void apply(MetavoxelData& data) const;
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(RemoveSpannerEdit)
|
||||
|
@ -159,9 +156,24 @@ public:
|
|||
|
||||
ClearSpannersEdit(const AttributePointer& attribute = AttributePointer());
|
||||
|
||||
virtual void apply(MetavoxelData& data) const;
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(ClearSpannersEdit)
|
||||
|
||||
/// An edit that sets a spanner's attributes in the voxel tree.
|
||||
class SetSpannerEdit : public MetavoxelEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM SharedObjectPointer spanner;
|
||||
|
||||
SetSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer());
|
||||
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(SetSpannerEdit)
|
||||
|
||||
#endif /* defined(__interface__MetavoxelMessages__) */
|
||||
|
|
|
@ -150,6 +150,12 @@ Box::Box(const glm::vec3& minimum, const glm::vec3& maximum) :
|
|||
minimum(minimum), maximum(maximum) {
|
||||
}
|
||||
|
||||
bool Box::contains(const glm::vec3& point) const {
|
||||
return point.x >= minimum.x && point.x <= maximum.x &&
|
||||
point.y >= minimum.y && point.y <= maximum.y &&
|
||||
point.z >= minimum.z && point.z <= maximum.z;
|
||||
}
|
||||
|
||||
bool Box::contains(const Box& other) const {
|
||||
return other.minimum.x >= minimum.x && other.maximum.x <= maximum.x &&
|
||||
other.minimum.y >= minimum.y && other.maximum.y <= maximum.y &&
|
||||
|
@ -162,6 +168,137 @@ bool Box::intersects(const Box& other) const {
|
|||
other.maximum.z >= minimum.z && other.minimum.z <= maximum.z;
|
||||
}
|
||||
|
||||
const int X_MAXIMUM_FLAG = 1;
|
||||
const int Y_MAXIMUM_FLAG = 2;
|
||||
const int Z_MAXIMUM_FLAG = 4;
|
||||
|
||||
glm::vec3 Box::getVertex(int index) const {
|
||||
return glm::vec3(
|
||||
(index & X_MAXIMUM_FLAG) ? maximum.x : minimum.x,
|
||||
(index & Y_MAXIMUM_FLAG) ? maximum.y : minimum.y,
|
||||
(index & Z_MAXIMUM_FLAG) ? maximum.z : minimum.z);
|
||||
}
|
||||
|
||||
// finds the intersection between a ray and the facing plane on one axis
|
||||
static bool findIntersection(float origin, float direction, float minimum, float maximum, float& distance) {
|
||||
if (direction > EPSILON) {
|
||||
distance = (minimum - origin) / direction;
|
||||
return true;
|
||||
} else if (direction < -EPSILON) {
|
||||
distance = (maximum - origin) / direction;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// determines whether a value is within the extents
|
||||
static bool isWithin(float value, float minimum, float maximum) {
|
||||
return value >= minimum && value <= maximum;
|
||||
}
|
||||
|
||||
bool Box::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
|
||||
// handle the trivial case where the box contains the origin
|
||||
if (contains(origin)) {
|
||||
distance = 0.0f;
|
||||
return true;
|
||||
}
|
||||
// check each axis
|
||||
float axisDistance;
|
||||
if ((findIntersection(origin.x, direction.x, minimum.x, maximum.x, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.y + axisDistance*direction.y, minimum.y, maximum.y) &&
|
||||
isWithin(origin.z + axisDistance*direction.z, minimum.z, maximum.z))) {
|
||||
distance = axisDistance;
|
||||
return true;
|
||||
}
|
||||
if ((findIntersection(origin.y, direction.y, minimum.y, maximum.y, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.x + axisDistance*direction.x, minimum.x, maximum.x) &&
|
||||
isWithin(origin.z + axisDistance*direction.z, minimum.z, maximum.z))) {
|
||||
distance = axisDistance;
|
||||
return true;
|
||||
}
|
||||
if ((findIntersection(origin.z, direction.z, minimum.z, maximum.z, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.y + axisDistance*direction.y, minimum.y, maximum.y) &&
|
||||
isWithin(origin.x + axisDistance*direction.x, minimum.x, maximum.x))) {
|
||||
distance = axisDistance;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Box operator*(const glm::mat4& matrix, const Box& box) {
|
||||
// start with the constant component
|
||||
Box newBox(glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]), glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]));
|
||||
|
||||
// for each element, we choose the minimum or maximum based on the matrix sign
|
||||
if (matrix[0][0] >= 0.0f) {
|
||||
newBox.minimum.x += matrix[0][0] * box.minimum.x;
|
||||
newBox.maximum.x += matrix[0][0] * box.maximum.x;
|
||||
} else {
|
||||
newBox.minimum.x += matrix[0][0] * box.maximum.x;
|
||||
newBox.maximum.x += matrix[0][0] * box.minimum.x;
|
||||
}
|
||||
if (matrix[1][0] >= 0.0f) {
|
||||
newBox.minimum.x += matrix[1][0] * box.minimum.y;
|
||||
newBox.maximum.x += matrix[1][0] * box.maximum.y;
|
||||
} else {
|
||||
newBox.minimum.x += matrix[1][0] * box.maximum.y;
|
||||
newBox.maximum.x += matrix[1][0] * box.minimum.y;
|
||||
}
|
||||
if (matrix[2][0] >= 0.0f) {
|
||||
newBox.minimum.x += matrix[2][0] * box.minimum.z;
|
||||
newBox.maximum.x += matrix[2][0] * box.maximum.z;
|
||||
} else {
|
||||
newBox.minimum.x += matrix[2][0] * box.maximum.z;
|
||||
newBox.maximum.x += matrix[2][0] * box.minimum.z;
|
||||
}
|
||||
|
||||
if (matrix[0][1] >= 0.0f) {
|
||||
newBox.minimum.y += matrix[0][1] * box.minimum.x;
|
||||
newBox.maximum.y += matrix[0][1] * box.maximum.x;
|
||||
} else {
|
||||
newBox.minimum.y += matrix[0][1] * box.maximum.x;
|
||||
newBox.maximum.y += matrix[0][1] * box.minimum.x;
|
||||
}
|
||||
if (matrix[1][1] >= 0.0f) {
|
||||
newBox.minimum.y += matrix[1][1] * box.minimum.y;
|
||||
newBox.maximum.y += matrix[1][1] * box.maximum.y;
|
||||
} else {
|
||||
newBox.minimum.y += matrix[1][1] * box.maximum.y;
|
||||
newBox.maximum.y += matrix[1][1] * box.minimum.y;
|
||||
}
|
||||
if (matrix[2][1] >= 0.0f) {
|
||||
newBox.minimum.y += matrix[2][1] * box.minimum.z;
|
||||
newBox.maximum.y += matrix[2][1] * box.maximum.z;
|
||||
} else {
|
||||
newBox.minimum.y += matrix[2][1] * box.maximum.z;
|
||||
newBox.maximum.y += matrix[2][1] * box.minimum.z;
|
||||
}
|
||||
|
||||
if (matrix[0][2] >= 0.0f) {
|
||||
newBox.minimum.z += matrix[0][2] * box.minimum.x;
|
||||
newBox.maximum.z += matrix[0][2] * box.maximum.x;
|
||||
} else {
|
||||
newBox.minimum.z += matrix[0][2] * box.maximum.x;
|
||||
newBox.maximum.z += matrix[0][2] * box.minimum.x;
|
||||
}
|
||||
if (matrix[1][2] >= 0.0f) {
|
||||
newBox.minimum.z += matrix[1][2] * box.minimum.y;
|
||||
newBox.maximum.z += matrix[1][2] * box.maximum.y;
|
||||
} else {
|
||||
newBox.minimum.z += matrix[1][2] * box.maximum.y;
|
||||
newBox.maximum.z += matrix[1][2] * box.minimum.y;
|
||||
}
|
||||
if (matrix[2][2] >= 0.0f) {
|
||||
newBox.minimum.z += matrix[2][2] * box.minimum.z;
|
||||
newBox.maximum.z += matrix[2][2] * box.maximum.z;
|
||||
} else {
|
||||
newBox.minimum.z += matrix[2][2] * box.maximum.z;
|
||||
newBox.maximum.z += matrix[2][2] * box.minimum.z;
|
||||
}
|
||||
|
||||
return newBox;
|
||||
}
|
||||
|
||||
QMetaObjectEditor::QMetaObjectEditor(QWidget* parent) : QWidget(parent) {
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setContentsMargins(QMargins());
|
||||
|
|
|
@ -34,20 +34,32 @@ class Box {
|
|||
|
||||
public:
|
||||
|
||||
static const int VERTEX_COUNT = 8;
|
||||
|
||||
STREAM glm::vec3 minimum;
|
||||
STREAM glm::vec3 maximum;
|
||||
|
||||
Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3());
|
||||
|
||||
bool contains(const glm::vec3& point) const;
|
||||
|
||||
bool contains(const Box& other) const;
|
||||
|
||||
bool intersects(const Box& other) const;
|
||||
|
||||
float getLongestSide() const { return qMax(qMax(maximum.x - minimum.x, maximum.y - minimum.y), maximum.z - minimum.z); }
|
||||
|
||||
glm::vec3 getVertex(int index) const;
|
||||
|
||||
glm::vec3 getCenter() const { return (minimum + maximum) * 0.5f; }
|
||||
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(Box)
|
||||
|
||||
Box operator*(const glm::mat4& matrix, const Box& box);
|
||||
|
||||
/// Editor for meta-object values.
|
||||
class QMetaObjectEditor : public QWidget {
|
||||
Q_OBJECT
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue