mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 21:43:03 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into injected-audio
This commit is contained in:
commit
9c39bcba4c
53 changed files with 2179 additions and 284 deletions
|
@ -9,11 +9,12 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
|
||||||
|
|
||||||
find_package(Qt5Network REQUIRED)
|
find_package(Qt5Network REQUIRED)
|
||||||
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
|
||||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||||
|
|
||||||
qt5_use_modules(${TARGET_NAME} Network)
|
qt5_use_modules(${TARGET_NAME} Network Widgets)
|
||||||
|
|
||||||
# include glm
|
# include glm
|
||||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||||
|
@ -30,6 +31,7 @@ link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(octree-server ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(octree-server ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(particle-server ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(particle-server ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(voxel-server ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(voxel-server ${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
link_hifi_library(script-engine ${TARGET_NAME} ${ROOT_DIR})
|
||||||
#testing
|
#testing
|
||||||
|
|
||||||
include_directories(${ROOT_DIR}/externals/civetweb/include)
|
include_directories(${ROOT_DIR}/externals/civetweb/include)
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
Agent::Agent(const unsigned char* dataBuffer, int numBytes) :
|
Agent::Agent(const unsigned char* dataBuffer, int numBytes) :
|
||||||
ThreadedAssignment(dataBuffer, numBytes)
|
ThreadedAssignment(dataBuffer, numBytes)
|
||||||
{
|
{
|
||||||
_particleScriptingInterface.init();
|
|
||||||
_voxelScriptingInterface.init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
|
void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
|
||||||
|
@ -34,12 +32,12 @@ void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr&
|
||||||
// PACKET_TYPE_JURISDICTION, first byte is the node type...
|
// PACKET_TYPE_JURISDICTION, first byte is the node type...
|
||||||
switch (dataByteArray[headerBytes]) {
|
switch (dataByteArray[headerBytes]) {
|
||||||
case NODE_TYPE_VOXEL_SERVER:
|
case NODE_TYPE_VOXEL_SERVER:
|
||||||
_voxelScriptingInterface.getJurisdictionListener()->queueReceivedPacket(senderSockAddr,
|
_scriptEngine.getVoxelScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr,
|
||||||
(unsigned char*) dataByteArray.data(),
|
(unsigned char*) dataByteArray.data(),
|
||||||
dataByteArray.size());
|
dataByteArray.size());
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_PARTICLE_SERVER:
|
case NODE_TYPE_PARTICLE_SERVER:
|
||||||
_particleScriptingInterface.getJurisdictionListener()->queueReceivedPacket(senderSockAddr,
|
_scriptEngine.getParticleScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr,
|
||||||
(unsigned char*) dataByteArray.data(),
|
(unsigned char*) dataByteArray.data(),
|
||||||
dataByteArray.size());
|
dataByteArray.size());
|
||||||
break;
|
break;
|
||||||
|
@ -76,43 +74,12 @@ void Agent::run() {
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
|
||||||
QString scriptContents(reply->readAll());
|
QString scriptContents(reply->readAll());
|
||||||
QScriptEngine engine;
|
|
||||||
|
|
||||||
// register meta-type for glm::vec3 conversions
|
|
||||||
registerMetaTypes(&engine);
|
|
||||||
|
|
||||||
QScriptValue agentValue = engine.newQObject(this);
|
|
||||||
engine.globalObject().setProperty("Agent", agentValue);
|
|
||||||
|
|
||||||
QScriptValue voxelScripterValue = engine.newQObject(&_voxelScriptingInterface);
|
|
||||||
engine.globalObject().setProperty("Voxels", voxelScripterValue);
|
|
||||||
|
|
||||||
QScriptValue particleScripterValue = engine.newQObject(&_particleScriptingInterface);
|
|
||||||
engine.globalObject().setProperty("Particles", particleScripterValue);
|
|
||||||
|
|
||||||
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
|
|
||||||
engine.globalObject().setProperty("TREE_SCALE", treeScaleValue);
|
|
||||||
|
|
||||||
const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000;
|
|
||||||
|
|
||||||
// let the VoxelPacketSender know how frequently we plan to call it
|
|
||||||
_voxelScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS);
|
|
||||||
_particleScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS);
|
|
||||||
|
|
||||||
qDebug() << "Downloaded script:" << scriptContents << "\n";
|
qDebug() << "Downloaded script:" << scriptContents << "\n";
|
||||||
QScriptValue result = engine.evaluate(scriptContents);
|
|
||||||
qDebug() << "Evaluated script.\n";
|
|
||||||
|
|
||||||
if (engine.hasUncaughtException()) {
|
|
||||||
int line = engine.uncaughtExceptionLineNumber();
|
|
||||||
qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
timeval startTime;
|
timeval startTime;
|
||||||
gettimeofday(&startTime, NULL);
|
gettimeofday(&startTime, NULL);
|
||||||
|
|
||||||
int thisFrame = 0;
|
|
||||||
|
|
||||||
QTimer* domainServerTimer = new QTimer(this);
|
QTimer* domainServerTimer = new QTimer(this);
|
||||||
connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit()));
|
connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit()));
|
||||||
domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000);
|
domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000);
|
||||||
|
@ -124,50 +91,7 @@ void Agent::run() {
|
||||||
QTimer* pingNodesTimer = new QTimer(this);
|
QTimer* pingNodesTimer = new QTimer(this);
|
||||||
connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes()));
|
connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes()));
|
||||||
pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000);
|
pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000);
|
||||||
|
|
||||||
while (!_isFinished) {
|
|
||||||
|
|
||||||
int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * VISUAL_DATA_CALLBACK_USECS) - usecTimestampNow();
|
|
||||||
if (usecToSleep > 0) {
|
|
||||||
usleep(usecToSleep);
|
|
||||||
}
|
|
||||||
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
|
|
||||||
bool willSendVisualDataCallBack = false;
|
|
||||||
|
|
||||||
if (_voxelScriptingInterface.getVoxelPacketSender()->voxelServersExist()) {
|
|
||||||
// allow the scripter's call back to setup visual data
|
|
||||||
willSendVisualDataCallBack = true;
|
|
||||||
|
|
||||||
// release the queue of edit voxel messages.
|
|
||||||
_voxelScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages();
|
|
||||||
|
|
||||||
// since we're in non-threaded mode, call process so that the packets are sent
|
|
||||||
_voxelScriptingInterface.getVoxelPacketSender()->process();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_particleScriptingInterface.getParticlePacketSender()->serversExist()) {
|
_scriptEngine.setScriptContents(scriptContents);
|
||||||
// allow the scripter's call back to setup visual data
|
_scriptEngine.run();
|
||||||
willSendVisualDataCallBack = true;
|
|
||||||
|
|
||||||
// release the queue of edit voxel messages.
|
|
||||||
_particleScriptingInterface.getParticlePacketSender()->releaseQueuedMessages();
|
|
||||||
|
|
||||||
// since we're in non-threaded mode, call process so that the packets are sent
|
|
||||||
_particleScriptingInterface.getParticlePacketSender()->process();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (willSendVisualDataCallBack) {
|
|
||||||
emit willSendVisualDataCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (engine.hasUncaughtException()) {
|
|
||||||
int line = engine.uncaughtExceptionLineNumber();
|
|
||||||
qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
|
|
||||||
|
#include <ScriptEngine.h>
|
||||||
#include <ThreadedAssignment.h>
|
#include <ThreadedAssignment.h>
|
||||||
|
|
||||||
#include <VoxelScriptingInterface.h>
|
#include <VoxelScriptingInterface.h>
|
||||||
|
@ -33,8 +34,7 @@ signals:
|
||||||
void willSendAudioDataCallback();
|
void willSendAudioDataCallback();
|
||||||
void willSendVisualDataCallback();
|
void willSendVisualDataCallback();
|
||||||
private:
|
private:
|
||||||
VoxelScriptingInterface _voxelScriptingInterface;
|
ScriptEngine _scriptEngine;
|
||||||
ParticleScriptingInterface _particleScriptingInterface;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__Agent__) */
|
#endif /* defined(__hifi__Agent__) */
|
||||||
|
|
|
@ -220,12 +220,12 @@ void DomainServer::readAvailableDatagrams() {
|
||||||
}
|
}
|
||||||
} else if (packetData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) {
|
} else if (packetData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) {
|
||||||
|
|
||||||
qDebug("Received a request for assignment.\n");
|
|
||||||
|
|
||||||
if (_assignmentQueue.size() > 0) {
|
if (_assignmentQueue.size() > 0) {
|
||||||
// construct the requested assignment from the packet data
|
// construct the requested assignment from the packet data
|
||||||
Assignment requestAssignment(packetData, receivedBytes);
|
Assignment requestAssignment(packetData, receivedBytes);
|
||||||
|
|
||||||
|
qDebug("Received a request for assignment type %i from %s.\n", requestAssignment.getType(), qPrintable(senderSockAddr.getAddress().toString()));
|
||||||
|
|
||||||
Assignment* assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
|
Assignment* assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
|
||||||
|
|
||||||
if (assignmentToDeploy) {
|
if (assignmentToDeploy) {
|
||||||
|
@ -243,6 +243,8 @@ void DomainServer::readAvailableDatagrams() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
qDebug("Received an invalid assignment request from %s.\n", qPrintable(senderSockAddr.getAddress().toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,10 +93,11 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
link_hifi_library(metavoxels ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(scriptengine ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(script-engine ${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
|
||||||
# find required libraries
|
# find required libraries
|
||||||
find_package(Faceshift)
|
find_package(Faceshift)
|
||||||
|
@ -135,7 +136,7 @@ if (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
||||||
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
|
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
|
||||||
endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
||||||
|
|
||||||
qt5_use_modules(${TARGET_NAME} Core Gui Multimedia Network OpenGL Svg WebKit WebKitWidgets)
|
qt5_use_modules(${TARGET_NAME} Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets)
|
||||||
|
|
||||||
# include headers for interface and InterfaceConfig.
|
# include headers for interface and InterfaceConfig.
|
||||||
include_directories(
|
include_directories(
|
||||||
|
|
171
interface/resources/scripts/sphere.js
Normal file
171
interface/resources/scripts/sphere.js
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
//
|
||||||
|
// sphere.js
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 12/17/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
function strictIndexOf(array, element) {
|
||||||
|
for (var i = 0; i < array.length; i++) {
|
||||||
|
if (array[i] == element) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var colorIndex;
|
||||||
|
var normalIndex;
|
||||||
|
var visitor;
|
||||||
|
var info;
|
||||||
|
|
||||||
|
var MAX_DEPTH = 4;
|
||||||
|
|
||||||
|
var sphereCenter = [ 0.5, 0.5, 0.5 ];
|
||||||
|
var sphereColor = 0xFFFF00FF;
|
||||||
|
var sphereRadius = 0.25;
|
||||||
|
var sphereRadiusSquared = sphereRadius * sphereRadius;
|
||||||
|
|
||||||
|
function lengthSquared(x, y, z) {
|
||||||
|
return x*x + y*y + z*z;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setNormal(vector) {
|
||||||
|
if (normalIndex != -1) {
|
||||||
|
var length = Math.sqrt(lengthSquared(vector[0], vector[1], vector[2]));
|
||||||
|
if (length == 0.0) {
|
||||||
|
info.attributeValues[normalIndex] = 0x007F00;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
var scale = 127.0 / length;
|
||||||
|
info.attributeValues[normalIndex] =
|
||||||
|
(Math.floor(vector[0] * scale) & 0xFF) << 16 |
|
||||||
|
(Math.floor(vector[1] * scale) & 0xFF) << 8 |
|
||||||
|
Math.floor(vector[2] * scale) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function guide(minimum, size, depth) {
|
||||||
|
info.minimum = minimum;
|
||||||
|
info.size = size;
|
||||||
|
|
||||||
|
// start with a relative fast bounding volume test to find most non-intersecting states
|
||||||
|
var maximum = [ minimum[0] + size, minimum[1] + size, minimum[2] + size ];
|
||||||
|
if (minimum[0] >= sphereCenter[0] + sphereRadius ||
|
||||||
|
minimum[1] >= sphereCenter[1] + sphereRadius ||
|
||||||
|
minimum[2] >= sphereCenter[2] + sphereRadius ||
|
||||||
|
maximum[0] <= sphereCenter[0] - sphereRadius ||
|
||||||
|
maximum[1] <= sphereCenter[1] - sphereRadius ||
|
||||||
|
maximum[2] <= sphereCenter[2] - sphereRadius) {
|
||||||
|
info.isLeaf = true;
|
||||||
|
if (colorIndex != -1) {
|
||||||
|
info.attributeValues[colorIndex] = 0x0;
|
||||||
|
}
|
||||||
|
visitor.visit(info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var halfSize = size / 2;
|
||||||
|
var center = [ minimum[0] + halfSize, minimum[1] + halfSize, minimum[2] + halfSize ];
|
||||||
|
var vector = [ center[0] - sphereCenter[0], center[1] - sphereCenter[1], center[2] - sphereCenter[2] ];
|
||||||
|
|
||||||
|
// count the number of points inside the sphere
|
||||||
|
var inside = 0;
|
||||||
|
if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - minimum[2]) <=
|
||||||
|
sphereRadiusSquared) {
|
||||||
|
inside++;
|
||||||
|
}
|
||||||
|
if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - minimum[2]) <=
|
||||||
|
sphereRadiusSquared) {
|
||||||
|
inside++;
|
||||||
|
}
|
||||||
|
if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - minimum[2]) <=
|
||||||
|
sphereRadiusSquared) {
|
||||||
|
inside++;
|
||||||
|
}
|
||||||
|
if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - minimum[2]) <=
|
||||||
|
sphereRadiusSquared) {
|
||||||
|
inside++;
|
||||||
|
}
|
||||||
|
if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - maximum[2]) <=
|
||||||
|
sphereRadiusSquared) {
|
||||||
|
inside++;
|
||||||
|
}
|
||||||
|
if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - maximum[2]) <=
|
||||||
|
sphereRadiusSquared) {
|
||||||
|
inside++;
|
||||||
|
}
|
||||||
|
if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - maximum[2]) <=
|
||||||
|
sphereRadiusSquared) {
|
||||||
|
inside++;
|
||||||
|
}
|
||||||
|
if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - maximum[2]) <=
|
||||||
|
sphereRadiusSquared) {
|
||||||
|
inside++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if all points are in the sphere
|
||||||
|
if (inside == 8) {
|
||||||
|
info.isLeaf = true;
|
||||||
|
if (colorIndex != -1) {
|
||||||
|
info.attributeValues[colorIndex] = sphereColor;
|
||||||
|
}
|
||||||
|
setNormal(vector);
|
||||||
|
visitor.visit(info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we've reached max depth, compute alpha using a volume estimate
|
||||||
|
if (depth == MAX_DEPTH) {
|
||||||
|
info.isLeaf = true;
|
||||||
|
if (inside >= 3) {
|
||||||
|
if (colorIndex != -1) {
|
||||||
|
info.attributeValues[colorIndex] = sphereColor;
|
||||||
|
}
|
||||||
|
setNormal(vector);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (colorIndex != -1) {
|
||||||
|
info.attributeValues[colorIndex] = 0x0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visitor.visit(info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
info.isLeaf = false;
|
||||||
|
if (!visitor.visit(info)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
depth += 1;
|
||||||
|
guide(minimum, halfSize, depth);
|
||||||
|
guide([ center[0], minimum[1], minimum[2] ], halfSize, depth);
|
||||||
|
guide([ minimum[0], center[1], minimum[2] ], halfSize, depth);
|
||||||
|
guide([ center[0], center[1], minimum[2] ], halfSize, depth);
|
||||||
|
guide([ minimum[0], minimum[1], center[2] ], halfSize, depth);
|
||||||
|
guide([ center[0], minimum[1], center[2] ], halfSize, depth);
|
||||||
|
guide([ minimum[0], center[1], center[2] ], halfSize, depth);
|
||||||
|
guide([ center[0], center[1], center[2] ], halfSize, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
(function(visitation) {
|
||||||
|
var attributes = visitation.visitor.getAttributes();
|
||||||
|
colorIndex = strictIndexOf(attributes, AttributeRegistry.colorAttribute);
|
||||||
|
normalIndex = strictIndexOf(attributes, AttributeRegistry.normalAttribute);
|
||||||
|
visitor = visitation.visitor;
|
||||||
|
info = { attributeValues: new Array(attributes.length) };
|
||||||
|
|
||||||
|
// have the sphere orbit the center and pulse in size
|
||||||
|
var time = new Date().getTime();
|
||||||
|
var ROTATE_PERIOD = 400.0;
|
||||||
|
sphereCenter[0] = 0.5 + 0.25 * Math.cos(time / ROTATE_PERIOD);
|
||||||
|
sphereCenter[2] = 0.5 + 0.25 * Math.sin(time / ROTATE_PERIOD);
|
||||||
|
var PULSE_PERIOD = 300.0;
|
||||||
|
sphereRadius = 0.25 + 0.0625 * Math.cos(time / PULSE_PERIOD);
|
||||||
|
sphereRadiusSquared = sphereRadius * sphereRadius;
|
||||||
|
|
||||||
|
guide(visitation.info.minimum, visitation.info.size, 0);
|
||||||
|
})
|
25
interface/resources/shaders/metavoxel_point.vert
Normal file
25
interface/resources/shaders/metavoxel_point.vert
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// metavoxel_point.vert
|
||||||
|
// vertex shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 12/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
uniform float pointScale;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
|
||||||
|
// standard diffuse lighting
|
||||||
|
gl_FrontColor = vec4(gl_Color.rgb * (gl_LightModel.ambient.rgb + gl_LightSource[0].ambient.rgb +
|
||||||
|
gl_LightSource[0].diffuse.rgb * max(0.0, dot(gl_NormalMatrix * gl_Normal, gl_LightSource[0].position.xyz))),
|
||||||
|
gl_Color.a);
|
||||||
|
|
||||||
|
// extract the first three components of the vertex for position
|
||||||
|
gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0);
|
||||||
|
|
||||||
|
// the final component is the size in world space
|
||||||
|
gl_PointSize = pointScale * gl_Vertex.w / gl_Position.w;
|
||||||
|
}
|
BIN
interface/resources/styles/Inconsolata.otf
Normal file
BIN
interface/resources/styles/Inconsolata.otf
Normal file
Binary file not shown.
7
interface/resources/styles/log_dialog.qss
Normal file
7
interface/resources/styles/log_dialog.qss
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
QPlainTextEdit {
|
||||||
|
font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;
|
||||||
|
font-size: 16px;
|
||||||
|
padding-left: 28px;
|
||||||
|
color: #333333;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
|
@ -143,11 +143,17 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_pasteMode(false)
|
_pasteMode(false)
|
||||||
{
|
{
|
||||||
_applicationStartupTime = startup_time;
|
_applicationStartupTime = startup_time;
|
||||||
|
|
||||||
|
switchToResourcesParentIfRequired();
|
||||||
|
QFontDatabase::addApplicationFont("resources/styles/Inconsolata.otf");
|
||||||
_window->setWindowTitle("Interface");
|
_window->setWindowTitle("Interface");
|
||||||
|
|
||||||
qDebug( "[VERSION] Build sequence: %i", BUILD_VERSION);
|
|
||||||
|
|
||||||
qInstallMessageHandler(messageHandler);
|
qInstallMessageHandler(messageHandler);
|
||||||
|
|
||||||
|
// call Menu getInstance static method to set up the menu
|
||||||
|
_window->setMenuBar(Menu::getInstance());
|
||||||
|
|
||||||
|
qDebug("[VERSION] Build sequence: %i", BUILD_VERSION);
|
||||||
|
|
||||||
unsigned int listenPort = 0; // bind to an ephemeral port by default
|
unsigned int listenPort = 0; // bind to an ephemeral port by default
|
||||||
const char** constArgv = const_cast<const char**>(argv);
|
const char** constArgv = const_cast<const char**>(argv);
|
||||||
|
@ -173,16 +179,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
|
|
||||||
// network receive thread and voxel parsing thread are both controlled by the --nonblocking command line
|
// network receive thread and voxel parsing thread are both controlled by the --nonblocking command line
|
||||||
_enableProcessVoxelsThread = _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking");
|
_enableProcessVoxelsThread = _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking");
|
||||||
|
|
||||||
// setup QSettings
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
QString resourcesPath = QCoreApplication::applicationDirPath() + "/../Resources";
|
|
||||||
#else
|
|
||||||
QString resourcesPath = QCoreApplication::applicationDirPath() + "/resources";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
||||||
QSettings applicationInfo(resourcesPath + "/info/ApplicationInfo.ini", QSettings::IniFormat);
|
QSettings applicationInfo("resources/info/ApplicationInfo.ini", QSettings::IniFormat);
|
||||||
|
|
||||||
// set the associated application properties
|
// set the associated application properties
|
||||||
applicationInfo.beginGroup("INFO");
|
applicationInfo.beginGroup("INFO");
|
||||||
|
@ -191,11 +190,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
setApplicationVersion(applicationInfo.value("version").toString());
|
setApplicationVersion(applicationInfo.value("version").toString());
|
||||||
setOrganizationName(applicationInfo.value("organizationName").toString());
|
setOrganizationName(applicationInfo.value("organizationName").toString());
|
||||||
setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
|
setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
|
||||||
|
|
||||||
_settings = new QSettings(this);
|
_settings = new QSettings(this);
|
||||||
|
|
||||||
// call Menu getInstance static method to set up the menu
|
|
||||||
_window->setMenuBar(Menu::getInstance());
|
|
||||||
|
|
||||||
// Check to see if the user passed in a command line option for loading a local
|
// Check to see if the user passed in a command line option for loading a local
|
||||||
// Voxel File.
|
// Voxel File.
|
||||||
|
@ -251,6 +247,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application() {
|
Application::~Application() {
|
||||||
|
|
||||||
|
qInstallMessageHandler(NULL);
|
||||||
|
|
||||||
// make sure we don't call the idle timer any more
|
// make sure we don't call the idle timer any more
|
||||||
delete idleTimer;
|
delete idleTimer;
|
||||||
|
|
||||||
|
@ -1858,6 +1857,8 @@ void Application::init() {
|
||||||
_particles.init();
|
_particles.init();
|
||||||
_particles.setViewFrustum(getViewFrustum());
|
_particles.setViewFrustum(getViewFrustum());
|
||||||
|
|
||||||
|
_metavoxels.init();
|
||||||
|
|
||||||
_particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_myAvatar);
|
_particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_myAvatar);
|
||||||
|
|
||||||
_palette.init(_glWidget->width(), _glWidget->height());
|
_palette.init(_glWidget->width(), _glWidget->height());
|
||||||
|
@ -2376,6 +2377,15 @@ void Application::updateParticles(float deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::updateMetavoxels(float deltaTime) {
|
||||||
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
|
PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()");
|
||||||
|
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) {
|
||||||
|
_metavoxels.simulate(deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::updateTransmitter(float deltaTime) {
|
void Application::updateTransmitter(float deltaTime) {
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateTransmitter()");
|
PerformanceWarning warn(showWarnings, "Application::updateTransmitter()");
|
||||||
|
@ -2521,6 +2531,7 @@ void Application::update(float deltaTime) {
|
||||||
updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); //loop through all the other avatars and simulate them...
|
updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); //loop through all the other avatars and simulate them...
|
||||||
updateMyAvatarSimulation(deltaTime); // Simulate myself
|
updateMyAvatarSimulation(deltaTime); // Simulate myself
|
||||||
updateParticles(deltaTime); // Simulate particle cloud movements
|
updateParticles(deltaTime); // Simulate particle cloud movements
|
||||||
|
updateMetavoxels(deltaTime); // update metavoxels
|
||||||
updateTransmitter(deltaTime); // transmitter drive or pick
|
updateTransmitter(deltaTime); // transmitter drive or pick
|
||||||
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
|
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
|
||||||
updateDialogs(deltaTime); // update various stats dialogs if present
|
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||||
|
@ -3068,6 +3079,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// also, metavoxels
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... metavoxels...");
|
||||||
|
_metavoxels.render();
|
||||||
|
}
|
||||||
|
|
||||||
// render particles...
|
// render particles...
|
||||||
_particles.render();
|
_particles.render();
|
||||||
|
|
||||||
|
@ -4432,7 +4450,8 @@ void Application::loadScript() {
|
||||||
bool wantMenuItems = true; // tells the ScriptEngine object to add menu items for itself
|
bool wantMenuItems = true; // tells the ScriptEngine object to add menu items for itself
|
||||||
|
|
||||||
|
|
||||||
ScriptEngine* scriptEngine = new ScriptEngine(script, wantMenuItems, fileName, Menu::getInstance());
|
ScriptEngine* scriptEngine = new ScriptEngine(script, wantMenuItems, fileName, Menu::getInstance(),
|
||||||
|
&_controllerScriptingInterface);
|
||||||
scriptEngine->setupMenuItems();
|
scriptEngine->setupMenuItems();
|
||||||
|
|
||||||
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
|
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
|
||||||
|
@ -4460,3 +4479,12 @@ void Application::loadScript() {
|
||||||
// restore the main window's active state
|
// restore the main window's active state
|
||||||
_window->activateWindow();
|
_window->activateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::toggleLogDialog() {
|
||||||
|
if (! _logDialog) {
|
||||||
|
_logDialog = new LogDialog(_glWidget);
|
||||||
|
_logDialog->show();
|
||||||
|
} else {
|
||||||
|
_logDialog->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QTouchEvent>
|
#include <QTouchEvent>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
#include <NetworkPacket.h>
|
#include <NetworkPacket.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
|
@ -58,16 +59,20 @@
|
||||||
#include "renderer/AmbientOcclusionEffect.h"
|
#include "renderer/AmbientOcclusionEffect.h"
|
||||||
#include "renderer/GeometryCache.h"
|
#include "renderer/GeometryCache.h"
|
||||||
#include "renderer/GlowEffect.h"
|
#include "renderer/GlowEffect.h"
|
||||||
#include "renderer/VoxelShader.h"
|
#include "renderer/MetavoxelSystem.h"
|
||||||
#include "renderer/PointShader.h"
|
#include "renderer/PointShader.h"
|
||||||
#include "renderer/TextureCache.h"
|
#include "renderer/TextureCache.h"
|
||||||
|
#include "renderer/VoxelShader.h"
|
||||||
#include "ui/BandwidthDialog.h"
|
#include "ui/BandwidthDialog.h"
|
||||||
#include "ui/ChatEntry.h"
|
#include "ui/ChatEntry.h"
|
||||||
#include "ui/VoxelStatsDialog.h"
|
#include "ui/VoxelStatsDialog.h"
|
||||||
#include "ui/RearMirrorTools.h"
|
#include "ui/RearMirrorTools.h"
|
||||||
#include "ui/LodToolsDialog.h"
|
#include "ui/LodToolsDialog.h"
|
||||||
|
#include "ui/LogDialog.h"
|
||||||
#include "ParticleTreeRenderer.h"
|
#include "ParticleTreeRenderer.h"
|
||||||
#include "ParticleEditHandle.h"
|
#include "ParticleEditHandle.h"
|
||||||
|
#include "ControllerScriptingInterface.h"
|
||||||
|
|
||||||
|
|
||||||
class QAction;
|
class QAction;
|
||||||
class QActionGroup;
|
class QActionGroup;
|
||||||
|
@ -221,7 +226,7 @@ public slots:
|
||||||
void decreaseVoxelSize();
|
void decreaseVoxelSize();
|
||||||
void increaseVoxelSize();
|
void increaseVoxelSize();
|
||||||
void loadScript();
|
void loadScript();
|
||||||
|
void toggleLogDialog();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
@ -282,6 +287,7 @@ private:
|
||||||
void updateThreads(float deltaTime);
|
void updateThreads(float deltaTime);
|
||||||
void updateMyAvatarSimulation(float deltaTime);
|
void updateMyAvatarSimulation(float deltaTime);
|
||||||
void updateParticles(float deltaTime);
|
void updateParticles(float deltaTime);
|
||||||
|
void updateMetavoxels(float deltaTime);
|
||||||
void updateTransmitter(float deltaTime);
|
void updateTransmitter(float deltaTime);
|
||||||
void updateCamera(float deltaTime);
|
void updateCamera(float deltaTime);
|
||||||
void updateDialogs(float deltaTime);
|
void updateDialogs(float deltaTime);
|
||||||
|
@ -362,6 +368,8 @@ private:
|
||||||
QByteArray _voxelsFilename;
|
QByteArray _voxelsFilename;
|
||||||
bool _wantToKillLocalVoxels;
|
bool _wantToKillLocalVoxels;
|
||||||
|
|
||||||
|
MetavoxelSystem _metavoxels;
|
||||||
|
|
||||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||||
|
|
||||||
Oscilloscope _audioScope;
|
Oscilloscope _audioScope;
|
||||||
|
@ -499,6 +507,8 @@ private:
|
||||||
|
|
||||||
std::vector<VoxelFade> _voxelFades;
|
std::vector<VoxelFade> _voxelFades;
|
||||||
std::vector<Avatar*> _avatarFades;
|
std::vector<Avatar*> _avatarFades;
|
||||||
|
ControllerScriptingInterface _controllerScriptingInterface;
|
||||||
|
QPointer<LogDialog> _logDialog;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__Application__) */
|
#endif /* defined(__interface__Application__) */
|
||||||
|
|
|
@ -174,9 +174,8 @@ void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples,
|
||||||
if (sourceAudioFormat == destinationAudioFormat) {
|
if (sourceAudioFormat == destinationAudioFormat) {
|
||||||
memcpy(destinationSamples, sourceSamples, numSourceSamples * sizeof(int16_t));
|
memcpy(destinationSamples, sourceSamples, numSourceSamples * sizeof(int16_t));
|
||||||
} else {
|
} else {
|
||||||
int destinationChannels = (destinationAudioFormat.channelCount() >= 2) ? 2 : destinationAudioFormat.channelCount();
|
|
||||||
float sourceToDestinationFactor = (sourceAudioFormat.sampleRate() / (float) destinationAudioFormat.sampleRate())
|
float sourceToDestinationFactor = (sourceAudioFormat.sampleRate() / (float) destinationAudioFormat.sampleRate())
|
||||||
* (sourceAudioFormat.channelCount() / (float) destinationChannels);
|
* (sourceAudioFormat.channelCount() / (float) destinationAudioFormat.channelCount());
|
||||||
|
|
||||||
// take into account the number of channels in source and destination
|
// take into account the number of channels in source and destination
|
||||||
// accomodate for the case where have an output with > 2 channels
|
// accomodate for the case where have an output with > 2 channels
|
||||||
|
@ -203,14 +202,15 @@ void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples,
|
||||||
// upsample from 24 to 48
|
// upsample from 24 to 48
|
||||||
// for now this only supports a stereo to stereo conversion - this is our case for network audio to output
|
// for now this only supports a stereo to stereo conversion - this is our case for network audio to output
|
||||||
int sourceIndex = 0;
|
int sourceIndex = 0;
|
||||||
int destinationToSourceFactor = (1 / sourceToDestinationFactor);
|
|
||||||
int dtsSampleRateFactor = (destinationAudioFormat.sampleRate() / sourceAudioFormat.sampleRate());
|
int dtsSampleRateFactor = (destinationAudioFormat.sampleRate() / sourceAudioFormat.sampleRate());
|
||||||
|
int sampleShift = destinationAudioFormat.channelCount() * dtsSampleRateFactor;
|
||||||
|
int destinationToSourceFactor = (1 / sourceToDestinationFactor);
|
||||||
|
|
||||||
for (int i = 0; i < numDestinationSamples; i += destinationAudioFormat.channelCount() * dtsSampleRateFactor) {
|
for (int i = 0; i < numDestinationSamples; i += sampleShift) {
|
||||||
sourceIndex = (i / destinationToSourceFactor);
|
sourceIndex = (i / destinationToSourceFactor);
|
||||||
|
|
||||||
// fill the L/R channels and make the rest silent
|
// fill the L/R channels and make the rest silent
|
||||||
for (int j = i; j < i + (dtsSampleRateFactor * destinationAudioFormat.channelCount()); j++) {
|
for (int j = i; j < i + sampleShift; j++) {
|
||||||
if (j % destinationAudioFormat.channelCount() == 0) {
|
if (j % destinationAudioFormat.channelCount() == 0) {
|
||||||
// left channel
|
// left channel
|
||||||
destinationSamples[j] = sourceSamples[sourceIndex];
|
destinationSamples[j] = sourceSamples[sourceIndex];
|
||||||
|
|
183
interface/src/ControllerScriptingInterface.cpp
Normal file
183
interface/src/ControllerScriptingInterface.cpp
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
//
|
||||||
|
// ControllerScriptingInterface.h
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 12/17/13
|
||||||
|
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <HandData.h>
|
||||||
|
#include "Application.h"
|
||||||
|
#include "ControllerScriptingInterface.h"
|
||||||
|
|
||||||
|
const PalmData* ControllerScriptingInterface::getPrimaryPalm() const {
|
||||||
|
int leftPalmIndex, rightPalmIndex;
|
||||||
|
|
||||||
|
const HandData* handData = Application::getInstance()->getAvatar()->getHandData();
|
||||||
|
handData->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
|
||||||
|
|
||||||
|
if (rightPalmIndex != -1) {
|
||||||
|
return &handData->getPalms()[rightPalmIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ControllerScriptingInterface::getNumberOfActivePalms() const {
|
||||||
|
const HandData* handData = Application::getInstance()->getAvatar()->getHandData();
|
||||||
|
int numberOfPalms = handData->getNumPalms();
|
||||||
|
int numberOfActivePalms = 0;
|
||||||
|
for (int i = 0; i < numberOfPalms; i++) {
|
||||||
|
if (getPalm(i)->isActive()) {
|
||||||
|
numberOfActivePalms++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return numberOfActivePalms;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PalmData* ControllerScriptingInterface::getPalm(int palmIndex) const {
|
||||||
|
const HandData* handData = Application::getInstance()->getAvatar()->getHandData();
|
||||||
|
return &handData->getPalms()[palmIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const {
|
||||||
|
const HandData* handData = Application::getInstance()->getAvatar()->getHandData();
|
||||||
|
int numberOfPalms = handData->getNumPalms();
|
||||||
|
int numberOfActivePalms = 0;
|
||||||
|
for (int i = 0; i < numberOfPalms; i++) {
|
||||||
|
if (getPalm(i)->isActive()) {
|
||||||
|
if (numberOfActivePalms == palmIndex) {
|
||||||
|
return &handData->getPalms()[i];
|
||||||
|
}
|
||||||
|
numberOfActivePalms++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControllerScriptingInterface::isPrimaryButtonPressed() const {
|
||||||
|
const PalmData* primaryPalm = getPrimaryPalm();
|
||||||
|
if (primaryPalm) {
|
||||||
|
if (primaryPalm->getControllerButtons() & BUTTON_FWD) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 ControllerScriptingInterface::getPrimaryJoystickPosition() const {
|
||||||
|
const PalmData* primaryPalm = getPrimaryPalm();
|
||||||
|
if (primaryPalm) {
|
||||||
|
return glm::vec2(primaryPalm->getJoystickX(), primaryPalm->getJoystickY());
|
||||||
|
}
|
||||||
|
|
||||||
|
return glm::vec2(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ControllerScriptingInterface::getNumberOfButtons() const {
|
||||||
|
return getNumberOfActivePalms() * NUMBER_OF_BUTTONS_PER_PALM;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControllerScriptingInterface::isButtonPressed(int buttonIndex) const {
|
||||||
|
int palmIndex = buttonIndex / NUMBER_OF_BUTTONS_PER_PALM;
|
||||||
|
int buttonOnPalm = buttonIndex % NUMBER_OF_BUTTONS_PER_PALM;
|
||||||
|
const PalmData* palmData = getActivePalm(palmIndex);
|
||||||
|
if (palmData) {
|
||||||
|
switch (buttonOnPalm) {
|
||||||
|
case 0:
|
||||||
|
return palmData->getControllerButtons() & BUTTON_0;
|
||||||
|
case 1:
|
||||||
|
return palmData->getControllerButtons() & BUTTON_1;
|
||||||
|
case 2:
|
||||||
|
return palmData->getControllerButtons() & BUTTON_2;
|
||||||
|
case 3:
|
||||||
|
return palmData->getControllerButtons() & BUTTON_3;
|
||||||
|
case 4:
|
||||||
|
return palmData->getControllerButtons() & BUTTON_4;
|
||||||
|
case 5:
|
||||||
|
return palmData->getControllerButtons() & BUTTON_FWD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ControllerScriptingInterface::getNumberOfTriggers() const {
|
||||||
|
return getNumberOfActivePalms() * NUMBER_OF_TRIGGERS_PER_PALM;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ControllerScriptingInterface::getTriggerValue(int triggerIndex) const {
|
||||||
|
// we know there's one trigger per palm, so the triggerIndex is the palm Index
|
||||||
|
int palmIndex = triggerIndex;
|
||||||
|
const PalmData* palmData = getActivePalm(palmIndex);
|
||||||
|
if (palmData) {
|
||||||
|
return palmData->getTrigger();
|
||||||
|
}
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ControllerScriptingInterface::getNumberOfJoysticks() const {
|
||||||
|
return getNumberOfActivePalms() * NUMBER_OF_JOYSTICKS_PER_PALM;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 ControllerScriptingInterface::getJoystickPosition(int joystickIndex) const {
|
||||||
|
// we know there's one joystick per palm, so the joystickIndex is the palm Index
|
||||||
|
int palmIndex = joystickIndex;
|
||||||
|
const PalmData* palmData = getActivePalm(palmIndex);
|
||||||
|
if (palmData) {
|
||||||
|
return glm::vec2(palmData->getJoystickX(), palmData->getJoystickY());
|
||||||
|
}
|
||||||
|
return glm::vec2(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ControllerScriptingInterface::getNumberOfSpatialControls() const {
|
||||||
|
return getNumberOfActivePalms() * NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 ControllerScriptingInterface::getSpatialControlPosition(int controlIndex) const {
|
||||||
|
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||||
|
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||||
|
const PalmData* palmData = getActivePalm(palmIndex);
|
||||||
|
if (palmData) {
|
||||||
|
switch (controlOfPalm) {
|
||||||
|
case PALM_SPATIALCONTROL:
|
||||||
|
return palmData->getPosition();
|
||||||
|
case TIP_SPATIALCONTROL:
|
||||||
|
return palmData->getTipPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return glm::vec3(0); // bad index
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 ControllerScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
|
||||||
|
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||||
|
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||||
|
const PalmData* palmData = getActivePalm(palmIndex);
|
||||||
|
if (palmData) {
|
||||||
|
switch (controlOfPalm) {
|
||||||
|
case PALM_SPATIALCONTROL:
|
||||||
|
return palmData->getVelocity();
|
||||||
|
case TIP_SPATIALCONTROL:
|
||||||
|
return palmData->getTipVelocity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return glm::vec3(0); // bad index
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex) const {
|
||||||
|
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||||
|
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||||
|
const PalmData* palmData = getActivePalm(palmIndex);
|
||||||
|
if (palmData) {
|
||||||
|
switch (controlOfPalm) {
|
||||||
|
case PALM_SPATIALCONTROL:
|
||||||
|
return palmData->getNormal();
|
||||||
|
case TIP_SPATIALCONTROL:
|
||||||
|
return palmData->getNormal(); // currently the tip doesn't have a unique normal, use the palm normal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return glm::vec3(0); // bad index
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
52
interface/src/ControllerScriptingInterface.h
Normal file
52
interface/src/ControllerScriptingInterface.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
//
|
||||||
|
// ControllerScriptingInterface.h
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 12/17/13
|
||||||
|
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __hifi__ControllerScriptingInterface__
|
||||||
|
#define __hifi__ControllerScriptingInterface__
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
|
#include <AbstractControllerScriptingInterface.h>
|
||||||
|
|
||||||
|
/// handles scripting of input controller commands from JS
|
||||||
|
class ControllerScriptingInterface : public AbstractControllerScriptingInterface {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual bool isPrimaryButtonPressed() const;
|
||||||
|
virtual glm::vec2 getPrimaryJoystickPosition() const;
|
||||||
|
|
||||||
|
virtual int getNumberOfButtons() const;
|
||||||
|
virtual bool isButtonPressed(int buttonIndex) const;
|
||||||
|
|
||||||
|
virtual int getNumberOfTriggers() const;
|
||||||
|
virtual float getTriggerValue(int triggerIndex) const;
|
||||||
|
|
||||||
|
virtual int getNumberOfJoysticks() const;
|
||||||
|
virtual glm::vec2 getJoystickPosition(int joystickIndex) const;
|
||||||
|
|
||||||
|
virtual int getNumberOfSpatialControls() const;
|
||||||
|
virtual glm::vec3 getSpatialControlPosition(int controlIndex) const;
|
||||||
|
virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const;
|
||||||
|
virtual glm::vec3 getSpatialControlNormal(int controlIndex) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const PalmData* getPrimaryPalm() const;
|
||||||
|
const PalmData* getPalm(int palmIndex) const;
|
||||||
|
int getNumberOfActivePalms() const;
|
||||||
|
const PalmData* getActivePalm(int palmIndex) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip
|
||||||
|
const int NUMBER_OF_JOYSTICKS_PER_PALM = 1;
|
||||||
|
const int NUMBER_OF_TRIGGERS_PER_PALM = 1;
|
||||||
|
const int NUMBER_OF_BUTTONS_PER_PALM = 6;
|
||||||
|
const int PALM_SPATIALCONTROL = 0;
|
||||||
|
const int TIP_SPATIALCONTROL = 1;
|
||||||
|
|
||||||
|
#endif /* defined(__hifi__ControllerScriptingInterface__) */
|
|
@ -6,12 +6,13 @@
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "LogDisplay.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include "LogDisplay.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -91,6 +92,7 @@ void LogDisplay::setCharacterSize(unsigned width, unsigned height) {
|
||||||
void LogDisplay::addMessage(const char* ptr) {
|
void LogDisplay::addMessage(const char* ptr) {
|
||||||
|
|
||||||
pthread_mutex_lock(& _mutex);
|
pthread_mutex_lock(& _mutex);
|
||||||
|
emit logReceived(ptr);
|
||||||
|
|
||||||
// T-pipe, if requested
|
// T-pipe, if requested
|
||||||
if (_stream != 0l) {
|
if (_stream != 0l) {
|
||||||
|
@ -118,7 +120,7 @@ void LogDisplay::addMessage(const char* ptr) {
|
||||||
_writePos = _chars;
|
_writePos = _chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++_writtenInLine >= _lineLength || c == '\0') {
|
if (c == '\0') {
|
||||||
|
|
||||||
// new line? store its start to the line buffer and mark next line as empty
|
// new line? store its start to the line buffer and mark next line as empty
|
||||||
++_lastLinePos;
|
++_lastLinePos;
|
||||||
|
@ -148,13 +150,24 @@ void LogDisplay::addMessage(const char* ptr) {
|
||||||
|
|
||||||
// remember start position in character buffer for next line and reset character count
|
// remember start position in character buffer for next line and reset character count
|
||||||
_writeLineStartPos = _writePos;
|
_writeLineStartPos = _writePos;
|
||||||
_writtenInLine = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(& _mutex);
|
pthread_mutex_unlock(& _mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList LogDisplay::getLogData() {
|
||||||
|
// wait for adding new log data whilr iterating over _lines
|
||||||
|
pthread_mutex_lock(& _mutex);
|
||||||
|
QStringList list;
|
||||||
|
int i = 0;
|
||||||
|
while (_lines[i] != *_lastLinePos) {
|
||||||
|
list.append(_lines[i++]);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(& _mutex);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Rendering
|
// Rendering
|
||||||
//
|
//
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
|
|
||||||
#include "ui/TextRenderer.h"
|
#include "ui/TextRenderer.h"
|
||||||
|
|
||||||
class LogDisplay {
|
class LogDisplay : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static LogDisplay instance;
|
static LogDisplay instance;
|
||||||
|
@ -43,6 +44,11 @@ public:
|
||||||
static unsigned const LINE_BUFFER_SIZE = 256; // number of lines that are buffered
|
static unsigned const LINE_BUFFER_SIZE = 256; // number of lines that are buffered
|
||||||
static unsigned const MAX_MESSAGE_LENGTH = 512; // maximum number of characters for a message
|
static unsigned const MAX_MESSAGE_LENGTH = 512; // maximum number of characters for a message
|
||||||
|
|
||||||
|
QStringList getLogData();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void logReceived(QString message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// use static 'instance' to access the single instance
|
// use static 'instance' to access the single instance
|
||||||
LogDisplay();
|
LogDisplay();
|
||||||
|
|
|
@ -265,7 +265,7 @@ Menu::Menu() :
|
||||||
|
|
||||||
addDisabledActionAndSeparator(viewMenu, "Stats");
|
addDisabledActionAndSeparator(viewMenu, "Stats");
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L);
|
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, appInstance, SLOT(toggleLogDialog()));
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, true);
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true);
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true);
|
||||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails()));
|
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails()));
|
||||||
|
@ -285,7 +285,8 @@ Menu::Menu() :
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ParticleCloud, 0, false);
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ParticleCloud, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false);
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false);
|
||||||
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, false);
|
||||||
|
|
||||||
|
|
||||||
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options");
|
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options");
|
||||||
|
|
||||||
|
@ -701,7 +702,7 @@ QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu,
|
||||||
action = destinationMenu->addAction(actionName);
|
action = destinationMenu->addAction(actionName);
|
||||||
action->setShortcut(shortcut);
|
action->setShortcut(shortcut);
|
||||||
}
|
}
|
||||||
action->setMenuRole(role);
|
action->setMenuRole(role);
|
||||||
|
|
||||||
_actionHash.insert(actionName, action);
|
_actionHash.insert(actionName, action);
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,6 @@ private:
|
||||||
int _boundaryLevelAdjust;
|
int _boundaryLevelAdjust;
|
||||||
QAction* _useVoxelShader;
|
QAction* _useVoxelShader;
|
||||||
int _maxVoxelPacketsPerSecond;
|
int _maxVoxelPacketsPerSecond;
|
||||||
|
|
||||||
QMenu* _activeScriptsMenu;
|
QMenu* _activeScriptsMenu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -219,6 +218,7 @@ namespace MenuOption {
|
||||||
const QString Login = "Login";
|
const QString Login = "Login";
|
||||||
const QString LookAtIndicator = "Look-at Indicator";
|
const QString LookAtIndicator = "Look-at Indicator";
|
||||||
const QString LookAtVectors = "Look-at Vectors";
|
const QString LookAtVectors = "Look-at Vectors";
|
||||||
|
const QString Metavoxels = "Metavoxels";
|
||||||
const QString Mirror = "Mirror";
|
const QString Mirror = "Mirror";
|
||||||
const QString MoveWithLean = "Move with Lean";
|
const QString MoveWithLean = "Move with Lean";
|
||||||
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
|
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
|
||||||
|
|
|
@ -338,8 +338,6 @@ void Avatar::render(bool forceRenderHead) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// returns true if the Leap controls any of the avatar's hands.
|
// returns true if the Leap controls any of the avatar's hands.
|
||||||
bool Avatar::updateLeapHandPositions() {
|
bool Avatar::updateLeapHandPositions() {
|
||||||
bool returnValue = false;
|
bool returnValue = false;
|
||||||
|
@ -443,8 +441,6 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
||||||
return glm::angleAxis(angle * proportion, axis);
|
return glm::angleAxis(angle * proportion, axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Avatar::renderBody(bool forceRenderHead) {
|
void Avatar::renderBody(bool forceRenderHead) {
|
||||||
|
|
||||||
if (_head.getVideoFace().isFullFrame()) {
|
if (_head.getVideoFace().isFullFrame()) {
|
||||||
|
|
|
@ -24,11 +24,11 @@ using namespace std;
|
||||||
const float FINGERTIP_VOXEL_SIZE = 0.05;
|
const float FINGERTIP_VOXEL_SIZE = 0.05;
|
||||||
const int TOY_BALL_HAND = 1;
|
const int TOY_BALL_HAND = 1;
|
||||||
const float TOY_BALL_RADIUS = 0.05f;
|
const float TOY_BALL_RADIUS = 0.05f;
|
||||||
const float TOY_BALL_DAMPING = 0.99f;
|
const float TOY_BALL_DAMPING = 0.1f;
|
||||||
const glm::vec3 NO_VELOCITY = glm::vec3(0,0,0);
|
const glm::vec3 NO_VELOCITY = glm::vec3(0,0,0);
|
||||||
const glm::vec3 NO_GRAVITY = glm::vec3(0,0,0);
|
const glm::vec3 NO_GRAVITY = glm::vec3(0,0,0);
|
||||||
const float NO_DAMPING = 0.f;
|
const float NO_DAMPING = 0.f;
|
||||||
const glm::vec3 TOY_BALL_GRAVITY = glm::vec3(0,-0.5,0);
|
const glm::vec3 TOY_BALL_GRAVITY = glm::vec3(0,-2.0,0);
|
||||||
const QString TOY_BALL_UPDATE_SCRIPT("");
|
const QString TOY_BALL_UPDATE_SCRIPT("");
|
||||||
const float PALM_COLLISION_RADIUS = 0.03f;
|
const float PALM_COLLISION_RADIUS = 0.03f;
|
||||||
const float CATCH_RADIUS = 0.2f;
|
const float CATCH_RADIUS = 0.2f;
|
||||||
|
@ -98,7 +98,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
|
||||||
|
|
||||||
// update the particle with it's new state...
|
// update the particle with it's new state...
|
||||||
#ifdef DEBUG_HAND
|
#ifdef DEBUG_HAND
|
||||||
qDebug("Update caught particle!\n");
|
qDebug("Caught!\n");
|
||||||
#endif
|
#endif
|
||||||
caughtParticle->updateParticle(newPosition,
|
caughtParticle->updateParticle(newPosition,
|
||||||
closestParticle->getRadius(),
|
closestParticle->getRadius(),
|
||||||
|
@ -108,6 +108,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
|
||||||
NO_DAMPING,
|
NO_DAMPING,
|
||||||
IN_HAND, // we just grabbed it!
|
IN_HAND, // we just grabbed it!
|
||||||
closestParticle->getUpdateScript());
|
closestParticle->getUpdateScript());
|
||||||
|
|
||||||
|
|
||||||
// now tell our hand about us having caught it...
|
// now tell our hand about us having caught it...
|
||||||
_toyBallInHand[handID] = true;
|
_toyBallInHand[handID] = true;
|
||||||
|
@ -115,6 +116,11 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
|
||||||
//printf(">>>>>>> caught... handID:%d particle ID:%d _toyBallInHand[handID] = true\n", handID, closestParticle->getID());
|
//printf(">>>>>>> caught... handID:%d particle ID:%d _toyBallInHand[handID] = true\n", handID, closestParticle->getID());
|
||||||
_ballParticleEditHandles[handID] = caughtParticle;
|
_ballParticleEditHandles[handID] = caughtParticle;
|
||||||
caughtParticle = NULL;
|
caughtParticle = NULL;
|
||||||
|
// Play a catch sound!
|
||||||
|
Application::getInstance()->getAudio()->startDrumSound(1.0,
|
||||||
|
300,
|
||||||
|
0.5,
|
||||||
|
0.05);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,11 +164,17 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
|
||||||
TOY_BALL_DAMPING,
|
TOY_BALL_DAMPING,
|
||||||
IN_HAND,
|
IN_HAND,
|
||||||
TOY_BALL_UPDATE_SCRIPT);
|
TOY_BALL_UPDATE_SCRIPT);
|
||||||
|
// Play a new ball sound
|
||||||
|
Application::getInstance()->getAudio()->startDrumSound(1.0,
|
||||||
|
2000,
|
||||||
|
0.5,
|
||||||
|
0.02);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Ball is in hand
|
// Ball is in hand
|
||||||
#ifdef DEBUG_HAND
|
#ifdef DEBUG_HAND
|
||||||
qDebug("Ball in hand\n");
|
//qDebug("Ball in hand\n");
|
||||||
#endif
|
#endif
|
||||||
glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition;
|
glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition;
|
||||||
_ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE,
|
_ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE,
|
||||||
|
@ -178,13 +190,14 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
|
||||||
// If toy ball just released, add velocity to it!
|
// If toy ball just released, add velocity to it!
|
||||||
if (_toyBallInHand[handID]) {
|
if (_toyBallInHand[handID]) {
|
||||||
|
|
||||||
|
const float THROWN_VELOCITY_SCALING = 1.5f;
|
||||||
_toyBallInHand[handID] = false;
|
_toyBallInHand[handID] = false;
|
||||||
glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition;
|
glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition;
|
||||||
glm::vec3 ballVelocity = ballFromHand ? palm.getRawVelocity() : palm.getTipVelocity();
|
glm::vec3 ballVelocity = ballFromHand ? palm.getRawVelocity() : palm.getTipVelocity();
|
||||||
glm::quat avatarRotation = _owningAvatar->getOrientation();
|
glm::quat avatarRotation = _owningAvatar->getOrientation();
|
||||||
ballVelocity = avatarRotation * ballVelocity;
|
ballVelocity = avatarRotation * ballVelocity;
|
||||||
|
ballVelocity *= THROWN_VELOCITY_SCALING;
|
||||||
|
|
||||||
// ball is no longer in hand...
|
|
||||||
#ifdef DEBUG_HAND
|
#ifdef DEBUG_HAND
|
||||||
qDebug("Threw ball, v = %.3f\n", glm::length(ballVelocity));
|
qDebug("Threw ball, v = %.3f\n", glm::length(ballVelocity));
|
||||||
#endif
|
#endif
|
||||||
|
@ -201,6 +214,13 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
|
||||||
// note: deleting the edit handle doesn't effect the actual particle
|
// note: deleting the edit handle doesn't effect the actual particle
|
||||||
delete _ballParticleEditHandles[handID];
|
delete _ballParticleEditHandles[handID];
|
||||||
_ballParticleEditHandles[handID] = NULL;
|
_ballParticleEditHandles[handID] = NULL;
|
||||||
|
|
||||||
|
// Play a throw sound
|
||||||
|
Application::getInstance()->getAudio()->startDrumSound(1.0,
|
||||||
|
3000,
|
||||||
|
0.5,
|
||||||
|
0.02);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,23 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
int main(int argc, const char * argv[]) {
|
int main(int argc, const char * argv[]) {
|
||||||
timeval startup_time;
|
timeval startup_time;
|
||||||
gettimeofday(&startup_time, NULL);
|
gettimeofday(&startup_time, NULL);
|
||||||
|
|
||||||
|
// Debug option to demonstrate that the client's local time does not
|
||||||
|
// need to be in sync with any other network node. This forces clock
|
||||||
|
// skew for the individual client
|
||||||
|
const char* CLOCK_SKEW = "--clockSkew";
|
||||||
|
const char* clockSkewOption = getCmdOption(argc, argv, CLOCK_SKEW);
|
||||||
|
if (clockSkewOption) {
|
||||||
|
int clockSkew = atoi(clockSkewOption);
|
||||||
|
usecTimestampNowForceClockSkew(clockSkew);
|
||||||
|
qDebug("clockSkewOption=%s clockSkew=%d\n", clockSkewOption, clockSkew);
|
||||||
|
}
|
||||||
|
|
||||||
int exitCode;
|
int exitCode;
|
||||||
{
|
{
|
||||||
Application app(argc, const_cast<char**>(argv), startup_time);
|
Application app(argc, const_cast<char**>(argv), startup_time);
|
||||||
|
|
122
interface/src/renderer/MetavoxelSystem.cpp
Normal file
122
interface/src/renderer/MetavoxelSystem.cpp
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
//
|
||||||
|
// MetavoxelSystem.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 12/10/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "MetavoxelSystem.h"
|
||||||
|
|
||||||
|
ProgramObject MetavoxelSystem::_program;
|
||||||
|
int MetavoxelSystem::_pointScaleLocation;
|
||||||
|
|
||||||
|
MetavoxelSystem::MetavoxelSystem() :
|
||||||
|
_pointVisitor(_points),
|
||||||
|
_buffer(QOpenGLBuffer::VertexBuffer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelSystem::init() {
|
||||||
|
if (!_program.isLinked()) {
|
||||||
|
switchToResourcesParentIfRequired();
|
||||||
|
_program.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/metavoxel_point.vert");
|
||||||
|
_program.link();
|
||||||
|
|
||||||
|
_pointScaleLocation = _program.uniformLocation("pointScale");
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeRegistry::getInstance()->configureScriptEngine(&_scriptEngine);
|
||||||
|
|
||||||
|
QFile scriptFile("resources/scripts/sphere.js");
|
||||||
|
scriptFile.open(QIODevice::ReadOnly);
|
||||||
|
QScriptValue guideFunction = _scriptEngine.evaluate(QTextStream(&scriptFile).readAll());
|
||||||
|
_data.setAttributeValue(MetavoxelPath(), AttributeValue(AttributeRegistry::getInstance()->getGuideAttribute(),
|
||||||
|
encodeInline(PolymorphicDataPointer(new ScriptedMetavoxelGuide(guideFunction)))));
|
||||||
|
|
||||||
|
_buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||||
|
_buffer.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelSystem::simulate(float deltaTime) {
|
||||||
|
_points.clear();
|
||||||
|
_data.guide(_pointVisitor);
|
||||||
|
|
||||||
|
_buffer.bind();
|
||||||
|
int bytes = _points.size() * sizeof(Point);
|
||||||
|
if (_buffer.size() < bytes) {
|
||||||
|
_buffer.allocate(_points.constData(), bytes);
|
||||||
|
} else {
|
||||||
|
_buffer.write(0, _points.constData(), bytes);
|
||||||
|
}
|
||||||
|
_buffer.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelSystem::render() {
|
||||||
|
int viewport[4];
|
||||||
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||||
|
const int VIEWPORT_WIDTH_INDEX = 2;
|
||||||
|
const int VIEWPORT_HEIGHT_INDEX = 3;
|
||||||
|
float viewportWidth = viewport[VIEWPORT_WIDTH_INDEX];
|
||||||
|
float viewportHeight = viewport[VIEWPORT_HEIGHT_INDEX];
|
||||||
|
float viewportDiagonal = sqrtf(viewportWidth*viewportWidth + viewportHeight*viewportHeight);
|
||||||
|
float worldDiagonal = glm::distance(Application::getInstance()->getViewFrustum()->getNearBottomLeft(),
|
||||||
|
Application::getInstance()->getViewFrustum()->getNearTopRight());
|
||||||
|
|
||||||
|
_program.bind();
|
||||||
|
_program.setUniformValue(_pointScaleLocation, viewportDiagonal *
|
||||||
|
Application::getInstance()->getViewFrustum()->getNearClip() / worldDiagonal);
|
||||||
|
|
||||||
|
_buffer.bind();
|
||||||
|
|
||||||
|
Point* pt = 0;
|
||||||
|
glVertexPointer(4, GL_FLOAT, sizeof(Point), &pt->vertex);
|
||||||
|
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Point), &pt->color);
|
||||||
|
glNormalPointer(GL_BYTE, sizeof(Point), &pt->normal);
|
||||||
|
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
|
|
||||||
|
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
|
||||||
|
|
||||||
|
glDrawArrays(GL_POINTS, 0, _points.size());
|
||||||
|
|
||||||
|
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
|
||||||
|
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
glDisableClientState(GL_NORMAL_ARRAY);
|
||||||
|
|
||||||
|
_buffer.release();
|
||||||
|
|
||||||
|
_program.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
MetavoxelSystem::PointVisitor::PointVisitor(QVector<Point>& points) :
|
||||||
|
MetavoxelVisitor(QVector<AttributePointer>() <<
|
||||||
|
AttributeRegistry::getInstance()->getColorAttribute() <<
|
||||||
|
AttributeRegistry::getInstance()->getNormalAttribute()),
|
||||||
|
_points(points) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetavoxelSystem::PointVisitor::visit(const MetavoxelInfo& info) {
|
||||||
|
if (!info.isLeaf) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
QRgb color = info.attributeValues.at(0).getInlineValue<QRgb>();
|
||||||
|
QRgb normal = info.attributeValues.at(1).getInlineValue<QRgb>();
|
||||||
|
int alpha = qAlpha(color);
|
||||||
|
if (alpha > 0) {
|
||||||
|
Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size),
|
||||||
|
{ qRed(color), qGreen(color), qBlue(color), alpha }, { qRed(normal), qGreen(normal), qBlue(normal) } };
|
||||||
|
_points.append(point);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
61
interface/src/renderer/MetavoxelSystem.h
Normal file
61
interface/src/renderer/MetavoxelSystem.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
//
|
||||||
|
// MetavoxelSystem.h
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 12/10/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __interface__MetavoxelSystem__
|
||||||
|
#define __interface__MetavoxelSystem__
|
||||||
|
|
||||||
|
#include <QOpenGLBuffer>
|
||||||
|
#include <QScriptEngine>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <MetavoxelData.h>
|
||||||
|
|
||||||
|
#include "ProgramObject.h"
|
||||||
|
|
||||||
|
/// Renders a metavoxel tree.
|
||||||
|
class MetavoxelSystem {
|
||||||
|
public:
|
||||||
|
|
||||||
|
MetavoxelSystem();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
void simulate(float deltaTime);
|
||||||
|
void render();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
class Point {
|
||||||
|
public:
|
||||||
|
glm::vec4 vertex;
|
||||||
|
quint8 color[4];
|
||||||
|
quint8 normal[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
class PointVisitor : public MetavoxelVisitor {
|
||||||
|
public:
|
||||||
|
PointVisitor(QVector<Point>& points);
|
||||||
|
virtual bool visit(const MetavoxelInfo& info);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVector<Point>& _points;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ProgramObject _program;
|
||||||
|
static int _pointScaleLocation;
|
||||||
|
|
||||||
|
QScriptEngine _scriptEngine;
|
||||||
|
MetavoxelData _data;
|
||||||
|
QVector<Point> _points;
|
||||||
|
PointVisitor _pointVisitor;
|
||||||
|
QOpenGLBuffer _buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__interface__MetavoxelSystem__) */
|
75
interface/src/ui/LogDialog.cpp
Normal file
75
interface/src/ui/LogDialog.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// LogDialog.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Stojce Slavkovski on 12/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QTextBlock>
|
||||||
|
#include <QtGui>
|
||||||
|
|
||||||
|
#include "SharedUtil.h"
|
||||||
|
#include "ui/LogDialog.h"
|
||||||
|
#include "LogDisplay.h"
|
||||||
|
|
||||||
|
const int INITIAL_WIDTH = 720;
|
||||||
|
const float INITIAL_HEIGHT_RATIO = 0.6f;
|
||||||
|
|
||||||
|
int cursorMeta = qRegisterMetaType<QTextCursor>("QTextCursor");
|
||||||
|
int blockMeta = qRegisterMetaType<QTextBlock>("QTextBlock");
|
||||||
|
|
||||||
|
LogDialog::LogDialog(QWidget* parent) : QDialog(parent, Qt::Dialog) {
|
||||||
|
|
||||||
|
setWindowTitle("Log");
|
||||||
|
|
||||||
|
_logTextBox = new QPlainTextEdit(this);
|
||||||
|
_logTextBox->setReadOnly(true);
|
||||||
|
_logTextBox->show();
|
||||||
|
|
||||||
|
switchToResourcesParentIfRequired();
|
||||||
|
QFile styleSheet("resources/styles/log_dialog.qss");
|
||||||
|
|
||||||
|
if (styleSheet.open(QIODevice::ReadOnly)) {
|
||||||
|
setStyleSheet(styleSheet.readAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
QDesktopWidget desktop;
|
||||||
|
QRect screen = desktop.screenGeometry();
|
||||||
|
resize(INITIAL_WIDTH, static_cast<int>(screen.height() * INITIAL_HEIGHT_RATIO));
|
||||||
|
move(screen.center() - rect().center());
|
||||||
|
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDialog::~LogDialog() {
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogDialog::showEvent(QShowEvent *e) {
|
||||||
|
_logTextBox->clear();
|
||||||
|
|
||||||
|
pthread_mutex_lock(& _mutex);
|
||||||
|
QStringList _logData = LogDisplay::instance.getLogData();
|
||||||
|
|
||||||
|
connect(&LogDisplay::instance, &LogDisplay::logReceived, this, &LogDialog::appendLogLine);
|
||||||
|
for(int i = 0; i < _logData.size(); ++i) {
|
||||||
|
appendLogLine(_logData[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(& _mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogDialog::resizeEvent(QResizeEvent *e) {
|
||||||
|
_logTextBox->resize(width(), height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogDialog::appendLogLine(QString logLine) {
|
||||||
|
if (isVisible()) {
|
||||||
|
pthread_mutex_lock(& _mutex);
|
||||||
|
_logTextBox->appendPlainText(logLine.simplified());
|
||||||
|
pthread_mutex_unlock(& _mutex);
|
||||||
|
_logTextBox->ensureCursorVisible();
|
||||||
|
}
|
||||||
|
}
|
36
interface/src/ui/LogDialog.h
Normal file
36
interface/src/ui/LogDialog.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
// LogDialog.h
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Stojce Slavkovski on 12/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __interface__LogDialog__
|
||||||
|
#define __interface__LogDialog__
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
|
||||||
|
class LogDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
LogDialog(QWidget* parent);
|
||||||
|
~LogDialog();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void appendLogLine(QString logLine);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent* e);
|
||||||
|
void showEvent(QShowEvent* e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPlainTextEdit* _logTextBox;
|
||||||
|
pthread_mutex_t _mutex;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -169,6 +169,9 @@ int HandData::decodeRemoteData(unsigned char* sourceBuffer) {
|
||||||
palm.setRawNormal(handNormal);
|
palm.setRawNormal(handNormal);
|
||||||
palm.setActive(true);
|
palm.setActive(true);
|
||||||
|
|
||||||
|
// For received data, set the sixense controller ID to match the order initialized and sent - 0 Left, 1 Right
|
||||||
|
palm.setSixenseID(handIndex);
|
||||||
|
|
||||||
for (unsigned int fingerIndex = 0; fingerIndex < numFingers; ++fingerIndex) {
|
for (unsigned int fingerIndex = 0; fingerIndex < numFingers; ++fingerIndex) {
|
||||||
if (fingerIndex < palm.getNumFingers()) {
|
if (fingerIndex < palm.getNumFingers()) {
|
||||||
FingerData& finger = palm.getFingers()[fingerIndex];
|
FingerData& finger = palm.getFingers()[fingerIndex];
|
||||||
|
|
|
@ -53,9 +53,10 @@ public:
|
||||||
glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const;
|
glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const;
|
||||||
glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const;
|
glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const;
|
||||||
|
|
||||||
std::vector<PalmData>& getPalms() { return _palms; }
|
std::vector<PalmData>& getPalms() { return _palms; }
|
||||||
size_t getNumPalms() { return _palms.size(); }
|
const std::vector<PalmData>& getPalms() const { return _palms; }
|
||||||
PalmData& addNewPalm();
|
size_t getNumPalms() const { return _palms.size(); }
|
||||||
|
PalmData& addNewPalm();
|
||||||
|
|
||||||
/// Finds the indices of the left and right palms according to their locations, or -1 if either or
|
/// Finds the indices of the left and right palms according to their locations, or -1 if either or
|
||||||
/// both is not found.
|
/// both is not found.
|
||||||
|
@ -137,17 +138,18 @@ public:
|
||||||
|
|
||||||
const glm::vec3& getRawPosition() const { return _rawPosition; }
|
const glm::vec3& getRawPosition() const { return _rawPosition; }
|
||||||
const glm::vec3& getRawNormal() const { return _rawNormal; }
|
const glm::vec3& getRawNormal() const { return _rawNormal; }
|
||||||
bool isActive() const { return _isActive; }
|
bool isActive() const { return _isActive; }
|
||||||
int getLeapID() const { return _leapID; }
|
int getLeapID() const { return _leapID; }
|
||||||
int getSixenseID() const { return _sixenseID; }
|
int getSixenseID() const { return _sixenseID; }
|
||||||
|
|
||||||
|
|
||||||
std::vector<FingerData>& getFingers() { return _fingers; }
|
std::vector<FingerData>& getFingers() { return _fingers; }
|
||||||
size_t getNumFingers() { return _fingers.size(); }
|
const std::vector<FingerData>& getFingers() const { return _fingers; }
|
||||||
|
size_t getNumFingers() const { return _fingers.size(); }
|
||||||
|
|
||||||
void setActive(bool active) { _isActive = active; }
|
void setActive(bool active) { _isActive = active; }
|
||||||
void setLeapID(int id) { _leapID = id; }
|
void setLeapID(int id) { _leapID = id; }
|
||||||
void setSixenseID(int id) { _sixenseID = id; }
|
void setSixenseID(int id) { _sixenseID = id; }
|
||||||
|
|
||||||
void setRawRotation(const glm::quat rawRotation) { _rawRotation = rawRotation; };
|
void setRawRotation(const glm::quat rawRotation) { _rawRotation = rawRotation; };
|
||||||
glm::quat getRawRotation() const { return _rawRotation; }
|
glm::quat getRawRotation() const { return _rawRotation; }
|
||||||
|
@ -164,27 +166,27 @@ public:
|
||||||
const glm::vec3& getTipVelocity() const { return _tipVelocity; }
|
const glm::vec3& getTipVelocity() const { return _tipVelocity; }
|
||||||
void setTipVelocity(const glm::vec3& velocity) { _tipVelocity = velocity; }
|
void setTipVelocity(const glm::vec3& velocity) { _tipVelocity = velocity; }
|
||||||
|
|
||||||
void incrementFramesWithoutData() { _numFramesWithoutData++; }
|
void incrementFramesWithoutData() { _numFramesWithoutData++; }
|
||||||
void resetFramesWithoutData() { _numFramesWithoutData = 0; }
|
void resetFramesWithoutData() { _numFramesWithoutData = 0; }
|
||||||
int getFramesWithoutData() const { return _numFramesWithoutData; }
|
int getFramesWithoutData() const { return _numFramesWithoutData; }
|
||||||
|
|
||||||
// Controller buttons
|
// Controller buttons
|
||||||
void setControllerButtons(int controllerButtons) { _controllerButtons = controllerButtons; }
|
void setControllerButtons(int controllerButtons) { _controllerButtons = controllerButtons; }
|
||||||
void setLastControllerButtons(int controllerButtons) { _lastControllerButtons = controllerButtons; }
|
void setLastControllerButtons(int controllerButtons) { _lastControllerButtons = controllerButtons; }
|
||||||
|
|
||||||
int getControllerButtons() { return _controllerButtons; }
|
int getControllerButtons() const { return _controllerButtons; }
|
||||||
int getLastControllerButtons() { return _lastControllerButtons; }
|
int getLastControllerButtons() const { return _lastControllerButtons; }
|
||||||
|
|
||||||
void setTrigger(float trigger) { _trigger = trigger; }
|
void setTrigger(float trigger) { _trigger = trigger; }
|
||||||
float getTrigger() { return _trigger; }
|
float getTrigger() const { return _trigger; }
|
||||||
void setJoystick(float joystickX, float joystickY) { _joystickX = joystickX; _joystickY = joystickY; }
|
void setJoystick(float joystickX, float joystickY) { _joystickX = joystickX; _joystickY = joystickY; }
|
||||||
float getJoystickX() { return _joystickX; }
|
float getJoystickX() const { return _joystickX; }
|
||||||
float getJoystickY() { return _joystickY; }
|
float getJoystickY() const { return _joystickY; }
|
||||||
|
|
||||||
bool getIsCollidingWithVoxel() { return _isCollidingWithVoxel; }
|
bool getIsCollidingWithVoxel() const { return _isCollidingWithVoxel; }
|
||||||
void setIsCollidingWithVoxel(bool isCollidingWithVoxel) { _isCollidingWithVoxel = isCollidingWithVoxel; }
|
void setIsCollidingWithVoxel(bool isCollidingWithVoxel) { _isCollidingWithVoxel = isCollidingWithVoxel; }
|
||||||
|
|
||||||
bool getIsCollidingWithPalm() { return _isCollidingWithPalm; }
|
bool getIsCollidingWithPalm() const { return _isCollidingWithPalm; }
|
||||||
void setIsCollidingWithPalm(bool isCollidingWithPalm) { _isCollidingWithPalm = isCollidingWithPalm; }
|
void setIsCollidingWithPalm(bool isCollidingWithPalm) { _isCollidingWithPalm = isCollidingWithPalm; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
20
libraries/metavoxels/CMakeLists.txt
Normal file
20
libraries/metavoxels/CMakeLists.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
|
set(ROOT_DIR ../..)
|
||||||
|
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||||
|
|
||||||
|
# setup for find modules
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||||
|
|
||||||
|
set(TARGET_NAME metavoxels)
|
||||||
|
|
||||||
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
|
||||||
|
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||||
|
setup_hifi_library(${TARGET_NAME})
|
||||||
|
|
||||||
|
qt5_use_modules(${TARGET_NAME} Widgets Script)
|
||||||
|
|
||||||
|
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||||
|
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
|
143
libraries/metavoxels/src/AttributeRegistry.cpp
Normal file
143
libraries/metavoxels/src/AttributeRegistry.cpp
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
//
|
||||||
|
// AttributeRegistry.cpp
|
||||||
|
// metavoxels
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 12/6/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QScriptEngine>
|
||||||
|
|
||||||
|
#include "AttributeRegistry.h"
|
||||||
|
#include "MetavoxelData.h"
|
||||||
|
|
||||||
|
AttributeRegistry AttributeRegistry::_instance;
|
||||||
|
|
||||||
|
AttributeRegistry::AttributeRegistry() :
|
||||||
|
_guideAttribute(registerAttribute(new PolymorphicAttribute("guide", PolymorphicDataPointer(new DefaultMetavoxelGuide())))),
|
||||||
|
_colorAttribute(registerAttribute(new QRgbAttribute("color"))),
|
||||||
|
_normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttributeRegistry::configureScriptEngine(QScriptEngine* engine) {
|
||||||
|
QScriptValue registry = engine->newObject();
|
||||||
|
registry.setProperty("colorAttribute", engine->newQObject(_colorAttribute.data()));
|
||||||
|
registry.setProperty("normalAttribute", engine->newQObject(_normalAttribute.data()));
|
||||||
|
registry.setProperty("getAttribute", engine->newFunction(getAttribute, 1));
|
||||||
|
engine->globalObject().setProperty("AttributeRegistry", registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) {
|
||||||
|
AttributePointer& pointer = _attributes[attribute->getName()];
|
||||||
|
if (!pointer) {
|
||||||
|
pointer = attribute;
|
||||||
|
}
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue AttributeRegistry::getAttribute(QScriptContext* context, QScriptEngine* engine) {
|
||||||
|
return engine->newQObject(_instance.getAttribute(context->argument(0).toString()).data(), QScriptEngine::QtOwnership,
|
||||||
|
QScriptEngine::PreferExistingWrapperObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeValue::AttributeValue(const AttributePointer& attribute) :
|
||||||
|
_attribute(attribute), _value(attribute ? attribute->getDefaultValue() : NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeValue::AttributeValue(const AttributePointer& attribute, void* value) :
|
||||||
|
_attribute(attribute), _value(value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void* AttributeValue::copy() const {
|
||||||
|
return _attribute->create(_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AttributeValue::isDefault() const {
|
||||||
|
return !_attribute || _attribute->equal(_value, _attribute->getDefaultValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AttributeValue::operator==(const AttributeValue& other) const {
|
||||||
|
return _attribute == other._attribute && (!_attribute || _attribute->equal(_value, other._value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AttributeValue::operator==(void* other) const {
|
||||||
|
return _attribute && _attribute->equal(_value, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
OwnedAttributeValue::OwnedAttributeValue(const AttributePointer& attribute) :
|
||||||
|
AttributeValue(attribute, attribute ? attribute->create() : NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
OwnedAttributeValue::OwnedAttributeValue(const AttributePointer& attribute, void* value) :
|
||||||
|
AttributeValue(attribute, attribute ? attribute->create(value) : NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
OwnedAttributeValue::OwnedAttributeValue(const AttributeValue& other) :
|
||||||
|
AttributeValue(other.getAttribute(), other.getAttribute() ? other.copy() : NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
OwnedAttributeValue::~OwnedAttributeValue() {
|
||||||
|
if (_attribute) {
|
||||||
|
_attribute->destroy(_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OwnedAttributeValue& OwnedAttributeValue::operator=(const AttributeValue& other) {
|
||||||
|
if (_attribute) {
|
||||||
|
_attribute->destroy(_value);
|
||||||
|
}
|
||||||
|
if ((_attribute = other.getAttribute())) {
|
||||||
|
_value = _attribute->create(other.getValue());
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attribute::Attribute(const QString& name) {
|
||||||
|
setObjectName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Attribute::~Attribute() {
|
||||||
|
}
|
||||||
|
|
||||||
|
QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) :
|
||||||
|
InlineAttribute<QRgb>(name, defaultValue) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QRgbAttribute::merge(void*& parent, void* children[]) const {
|
||||||
|
QRgb firstValue = decodeInline<QRgb>(children[0]);
|
||||||
|
int totalRed = qRed(firstValue);
|
||||||
|
int totalGreen = qGreen(firstValue);
|
||||||
|
int totalBlue = qBlue(firstValue);
|
||||||
|
int totalAlpha = qAlpha(firstValue);
|
||||||
|
bool allChildrenEqual = true;
|
||||||
|
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
|
||||||
|
QRgb value = decodeInline<QRgb>(children[i]);
|
||||||
|
totalRed += qRed(value);
|
||||||
|
totalGreen += qGreen(value);
|
||||||
|
totalBlue += qBlue(value);
|
||||||
|
totalAlpha += qAlpha(value);
|
||||||
|
allChildrenEqual &= (firstValue == value);
|
||||||
|
}
|
||||||
|
parent = encodeInline(qRgba(totalRed / MERGE_COUNT, totalGreen / MERGE_COUNT,
|
||||||
|
totalBlue / MERGE_COUNT, totalAlpha / MERGE_COUNT));
|
||||||
|
return allChildrenEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* QRgbAttribute::createFromScript(const QScriptValue& value, QScriptEngine* engine) const {
|
||||||
|
return encodeInline((QRgb)value.toUInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
PolymorphicData::~PolymorphicData() {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> PolymorphicData* QExplicitlySharedDataPointer<PolymorphicData>::clone() {
|
||||||
|
return d->clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PolymorphicAttribute::PolymorphicAttribute(const QString& name, const PolymorphicDataPointer& defaultValue) :
|
||||||
|
InlineAttribute<PolymorphicDataPointer>(name, defaultValue) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PolymorphicAttribute::merge(void*& parent, void* children[]) const {
|
||||||
|
return false;
|
||||||
|
}
|
275
libraries/metavoxels/src/AttributeRegistry.h
Normal file
275
libraries/metavoxels/src/AttributeRegistry.h
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
//
|
||||||
|
// AttributeRegistry.h
|
||||||
|
// metavoxels
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 12/6/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __interface__AttributeRegistry__
|
||||||
|
#define __interface__AttributeRegistry__
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QExplicitlySharedDataPointer>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSharedData>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "Bitstream.h"
|
||||||
|
|
||||||
|
class QScriptContext;
|
||||||
|
class QScriptEngine;
|
||||||
|
class QScriptValue;
|
||||||
|
|
||||||
|
class Attribute;
|
||||||
|
|
||||||
|
typedef QSharedPointer<Attribute> AttributePointer;
|
||||||
|
|
||||||
|
/// Maintains information about metavoxel attribute types.
|
||||||
|
class AttributeRegistry {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Returns a pointer to the singleton registry instance.
|
||||||
|
static AttributeRegistry* getInstance() { return &_instance; }
|
||||||
|
|
||||||
|
AttributeRegistry();
|
||||||
|
|
||||||
|
/// Configures the supplied script engine with the global AttributeRegistry property.
|
||||||
|
void configureScriptEngine(QScriptEngine* engine);
|
||||||
|
|
||||||
|
/// Registers an attribute with the system. The registry assumes ownership of the object.
|
||||||
|
/// \return either the pointer passed as an argument, if the attribute wasn't already registered, or the existing
|
||||||
|
/// attribute
|
||||||
|
AttributePointer registerAttribute(Attribute* attribute) { return registerAttribute(AttributePointer(attribute)); }
|
||||||
|
|
||||||
|
/// Registers an attribute with the system.
|
||||||
|
/// \return either the pointer passed as an argument, if the attribute wasn't already registered, or the existing
|
||||||
|
/// attribute
|
||||||
|
AttributePointer registerAttribute(AttributePointer attribute);
|
||||||
|
|
||||||
|
/// Retrieves an attribute by name.
|
||||||
|
AttributePointer getAttribute(const QString& name) const { return _attributes.value(name); }
|
||||||
|
|
||||||
|
/// Returns a reference to the standard PolymorphicDataPointer "guide" attribute.
|
||||||
|
const AttributePointer& getGuideAttribute() const { return _guideAttribute; }
|
||||||
|
|
||||||
|
/// Returns a reference to the standard QRgb "color" attribute.
|
||||||
|
const AttributePointer& getColorAttribute() const { return _colorAttribute; }
|
||||||
|
|
||||||
|
/// Returns a reference to the standard QRgb "normal" attribute.
|
||||||
|
const AttributePointer& getNormalAttribute() const { return _normalAttribute; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine);
|
||||||
|
|
||||||
|
static AttributeRegistry _instance;
|
||||||
|
|
||||||
|
QHash<QString, AttributePointer> _attributes;
|
||||||
|
AttributePointer _guideAttribute;
|
||||||
|
AttributePointer _colorAttribute;
|
||||||
|
AttributePointer _normalAttribute;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Converts a value to a void pointer.
|
||||||
|
template<class T> inline void* encodeInline(T value) {
|
||||||
|
return *(void**)&value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts a value from a void pointer.
|
||||||
|
template<class T> inline T decodeInline(void* value) {
|
||||||
|
return *(T*)&value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pairs an attribute value with its type.
|
||||||
|
class AttributeValue {
|
||||||
|
public:
|
||||||
|
|
||||||
|
AttributeValue(const AttributePointer& attribute = AttributePointer());
|
||||||
|
AttributeValue(const AttributePointer& attribute, void* value);
|
||||||
|
|
||||||
|
AttributePointer getAttribute() const { return _attribute; }
|
||||||
|
void* getValue() const { return _value; }
|
||||||
|
|
||||||
|
template<class T> void setInlineValue(T value) { _value = encodeInline(value); }
|
||||||
|
template<class T> T getInlineValue() const { return decodeInline<T>(_value); }
|
||||||
|
|
||||||
|
template<class T> T* getPointerValue() const { return static_cast<T*>(_value); }
|
||||||
|
|
||||||
|
void* copy() const;
|
||||||
|
|
||||||
|
bool isDefault() const;
|
||||||
|
|
||||||
|
bool operator==(const AttributeValue& other) const;
|
||||||
|
bool operator==(void* other) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
AttributePointer _attribute;
|
||||||
|
void* _value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assumes ownership of an attribute value.
|
||||||
|
class OwnedAttributeValue : public AttributeValue {
|
||||||
|
public:
|
||||||
|
|
||||||
|
OwnedAttributeValue(const AttributePointer& attribute = AttributePointer());
|
||||||
|
OwnedAttributeValue(const AttributePointer& attribute, void* value);
|
||||||
|
OwnedAttributeValue(const AttributeValue& other);
|
||||||
|
~OwnedAttributeValue();
|
||||||
|
|
||||||
|
OwnedAttributeValue& operator=(const AttributeValue& other);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Represents a registered attribute.
|
||||||
|
class Attribute : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const int MERGE_COUNT = 8;
|
||||||
|
|
||||||
|
Attribute(const QString& name);
|
||||||
|
virtual ~Attribute();
|
||||||
|
|
||||||
|
Q_INVOKABLE QString getName() const { return objectName(); }
|
||||||
|
|
||||||
|
void* create() const { return create(getDefaultValue()); }
|
||||||
|
virtual void* create(void* copy) const = 0;
|
||||||
|
virtual void destroy(void* value) const = 0;
|
||||||
|
|
||||||
|
virtual bool read(Bitstream& in, void*& value) const = 0;
|
||||||
|
virtual bool write(Bitstream& out, void* value) const = 0;
|
||||||
|
|
||||||
|
virtual bool equal(void* first, void* second) const = 0;
|
||||||
|
|
||||||
|
/// Merges the value of a parent and its children.
|
||||||
|
/// \return whether or not the children and parent values are all equal
|
||||||
|
virtual bool merge(void*& parent, void* children[]) const = 0;
|
||||||
|
|
||||||
|
virtual void* getDefaultValue() const = 0;
|
||||||
|
|
||||||
|
virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const { return create(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A simple attribute class that stores its values inline.
|
||||||
|
template<class T, int bits = 32> class InlineAttribute : public Attribute {
|
||||||
|
public:
|
||||||
|
|
||||||
|
InlineAttribute(const QString& name, const T& defaultValue = T()) : Attribute(name), _defaultValue(defaultValue) { }
|
||||||
|
|
||||||
|
virtual void* create(void* copy) const { void* value; new (&value) T(*(T*)©); return value; }
|
||||||
|
virtual void destroy(void* value) const { ((T*)&value)->~T(); }
|
||||||
|
|
||||||
|
virtual bool read(Bitstream& in, void*& value) const { value = getDefaultValue(); in.read(&value, bits); return false; }
|
||||||
|
virtual bool write(Bitstream& out, void* value) const { out.write(&value, bits); return false; }
|
||||||
|
|
||||||
|
virtual bool equal(void* first, void* second) const { return decodeInline<T>(first) == decodeInline<T>(second); }
|
||||||
|
|
||||||
|
virtual void* getDefaultValue() const { return encodeInline(_defaultValue); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
T _defaultValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides merging using the =, ==, += and /= operators.
|
||||||
|
template<class T, int bits = 32> class SimpleInlineAttribute : public InlineAttribute<T, bits> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
SimpleInlineAttribute(const QString& name, T defaultValue = T()) : InlineAttribute<T, bits>(name, defaultValue) { }
|
||||||
|
|
||||||
|
virtual bool merge(void*& parent, void* children[]) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int bits> inline bool SimpleInlineAttribute<T, bits>::merge(void*& parent, void* children[]) const {
|
||||||
|
T& merged = *(T*)&parent;
|
||||||
|
merged = decodeInline<T>(children[0]);
|
||||||
|
bool allChildrenEqual = true;
|
||||||
|
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
|
||||||
|
merged += decodeInline<T>(children[i]);
|
||||||
|
allChildrenEqual &= (decodeInline<T>(children[0]) == decodeInline<T>(children[i]));
|
||||||
|
}
|
||||||
|
merged /= Attribute::MERGE_COUNT;
|
||||||
|
return allChildrenEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provides appropriate averaging for RGBA values.
|
||||||
|
class QRgbAttribute : public InlineAttribute<QRgb> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
QRgbAttribute(const QString& name, QRgb defaultValue = QRgb());
|
||||||
|
|
||||||
|
virtual bool merge(void*& parent, void* children[]) const;
|
||||||
|
|
||||||
|
virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// An attribute class that stores pointers to its values.
|
||||||
|
template<class T> class PointerAttribute : public Attribute {
|
||||||
|
public:
|
||||||
|
|
||||||
|
PointerAttribute(const QString& name, T defaultValue = T()) : Attribute(name), _defaultValue(defaultValue) { }
|
||||||
|
|
||||||
|
virtual void* create(void* copy) const { new T(*static_cast<T*>(copy)); }
|
||||||
|
virtual void destroy(void* value) const { delete static_cast<T*>(value); }
|
||||||
|
|
||||||
|
virtual bool read(Bitstream& in, void*& value) const { in >> *static_cast<T*>(value); return true; }
|
||||||
|
virtual bool write(Bitstream& out, void* value) const { out << *static_cast<T*>(value); return true; }
|
||||||
|
|
||||||
|
virtual bool equal(void* first, void* second) const { return *static_cast<T*>(first) == *static_cast<T*>(second); }
|
||||||
|
|
||||||
|
virtual void* getDefaultValue() const { return const_cast<void*>((void*)&_defaultValue); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
T _defaultValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides merging using the =, ==, += and /= operators.
|
||||||
|
template<class T> class SimplePointerAttribute : public PointerAttribute<T> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
SimplePointerAttribute(const QString& name, T defaultValue = T()) : PointerAttribute<T>(name, defaultValue) { }
|
||||||
|
|
||||||
|
virtual bool merge(void*& parent, void* children[]) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T> inline bool SimplePointerAttribute<T>::merge(void*& parent, void* children[]) const {
|
||||||
|
T& merged = *static_cast<T*>(parent);
|
||||||
|
merged = *static_cast<T*>(children[0]);
|
||||||
|
bool allChildrenEqual = true;
|
||||||
|
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
|
||||||
|
merged += *static_cast<T*>(children[i]);
|
||||||
|
allChildrenEqual &= (*static_cast<T*>(children[0]) == *static_cast<T*>(children[i]));
|
||||||
|
}
|
||||||
|
merged /= Attribute::MERGE_COUNT;
|
||||||
|
return allChildrenEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Base class for polymorphic attribute data.
|
||||||
|
class PolymorphicData : public QSharedData {
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~PolymorphicData();
|
||||||
|
|
||||||
|
/// Creates a new clone of this object.
|
||||||
|
virtual PolymorphicData* clone() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> PolymorphicData* QExplicitlySharedDataPointer<PolymorphicData>::clone();
|
||||||
|
|
||||||
|
typedef QExplicitlySharedDataPointer<PolymorphicData> PolymorphicDataPointer;
|
||||||
|
|
||||||
|
/// Provides polymorphic streaming and averaging.
|
||||||
|
class PolymorphicAttribute : public InlineAttribute<PolymorphicDataPointer> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
PolymorphicAttribute(const QString& name, const PolymorphicDataPointer& defaultValue = PolymorphicDataPointer());
|
||||||
|
|
||||||
|
virtual bool merge(void*& parent, void* children[]) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__interface__AttributeRegistry__) */
|
81
libraries/metavoxels/src/Bitstream.cpp
Normal file
81
libraries/metavoxels/src/Bitstream.cpp
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
//
|
||||||
|
// Bitstream.cpp
|
||||||
|
// metavoxels
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 12/2/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
|
#include "Bitstream.h"
|
||||||
|
|
||||||
|
Bitstream::Bitstream(QDataStream& underlying)
|
||||||
|
: _underlying(underlying), _byte(0), _position(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const int BITS_IN_BYTE = 8;
|
||||||
|
const int LAST_BIT_POSITION = BITS_IN_BYTE - 1;
|
||||||
|
|
||||||
|
Bitstream& Bitstream::write(const void* data, int bits, int offset) {
|
||||||
|
const quint8* source = (const quint8*)data;
|
||||||
|
while (bits > 0) {
|
||||||
|
int bitsToWrite = qMin(BITS_IN_BYTE - _position, qMin(BITS_IN_BYTE - offset, bits));
|
||||||
|
_byte |= ((*source >> offset) & ((1 << bitsToWrite) - 1)) << _position;
|
||||||
|
if ((_position += bitsToWrite) == BITS_IN_BYTE) {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
if ((offset += bitsToWrite) == BITS_IN_BYTE) {
|
||||||
|
source++;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
bits -= bitsToWrite;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitstream& Bitstream::read(void* data, int bits, int offset) {
|
||||||
|
quint8* dest = (quint8*)data;
|
||||||
|
while (bits > 0) {
|
||||||
|
if (_position == 0) {
|
||||||
|
_underlying >> _byte;
|
||||||
|
}
|
||||||
|
int bitsToRead = qMin(BITS_IN_BYTE - _position, qMin(BITS_IN_BYTE - offset, bits));
|
||||||
|
*dest |= ((_byte >> _position) & ((1 << bitsToRead) - 1)) << offset;
|
||||||
|
_position = (_position + bitsToRead) & LAST_BIT_POSITION;
|
||||||
|
if ((offset += bitsToRead) == BITS_IN_BYTE) {
|
||||||
|
dest++;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
bits -= bitsToRead;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bitstream::flush() {
|
||||||
|
if (_position != 0) {
|
||||||
|
_underlying << _byte;
|
||||||
|
_byte = 0;
|
||||||
|
_position = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Bitstream& Bitstream::operator<<(bool value) {
|
||||||
|
if (value) {
|
||||||
|
_byte |= (1 << _position);
|
||||||
|
}
|
||||||
|
if (++_position == BITS_IN_BYTE) {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitstream& Bitstream::operator>>(bool& value) {
|
||||||
|
if (_position == 0) {
|
||||||
|
_underlying >> _byte;
|
||||||
|
}
|
||||||
|
value = _byte & (1 << _position);
|
||||||
|
_position = (_position + 1) & LAST_BIT_POSITION;
|
||||||
|
return *this;
|
||||||
|
}
|
45
libraries/metavoxels/src/Bitstream.h
Normal file
45
libraries/metavoxels/src/Bitstream.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
//
|
||||||
|
// Bitstream.h
|
||||||
|
// metavoxels
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 12/2/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __interface__Bitstream__
|
||||||
|
#define __interface__Bitstream__
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
class QDataStream;
|
||||||
|
|
||||||
|
/// A stream for bit-aligned data.
|
||||||
|
class Bitstream {
|
||||||
|
public:
|
||||||
|
|
||||||
|
Bitstream(QDataStream& underlying);
|
||||||
|
|
||||||
|
/// Writes a set of bits to the underlying stream.
|
||||||
|
/// \param bits the number of bits to write
|
||||||
|
/// \param offset the offset of the first bit
|
||||||
|
Bitstream& write(const void* data, int bits, int offset = 0);
|
||||||
|
|
||||||
|
/// Reads a set of bits from the underlying stream.
|
||||||
|
/// \param bits the number of bits to read
|
||||||
|
/// \param offset the offset of the first bit
|
||||||
|
Bitstream& read(void* data, int bits, int offset = 0);
|
||||||
|
|
||||||
|
/// Flushes any unwritten bits to the underlying stream.
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
Bitstream& operator<<(bool value);
|
||||||
|
Bitstream& operator>>(bool& value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QDataStream& _underlying;
|
||||||
|
quint8 _byte;
|
||||||
|
int _position;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__interface__Bitstream__) */
|
281
libraries/metavoxels/src/MetavoxelData.cpp
Normal file
281
libraries/metavoxels/src/MetavoxelData.cpp
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
//
|
||||||
|
// MetavoxelData.cpp
|
||||||
|
// metavoxels
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 12/6/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QScriptEngine>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
|
#include "MetavoxelData.h"
|
||||||
|
|
||||||
|
MetavoxelData::~MetavoxelData() {
|
||||||
|
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
||||||
|
it.value()->destroy(it.key());
|
||||||
|
delete it.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelData::guide(MetavoxelVisitor& visitor) {
|
||||||
|
// start with the root values/defaults (plus the guide attribute)
|
||||||
|
const float TOP_LEVEL_SIZE = 1.0f;
|
||||||
|
const QVector<AttributePointer>& attributes = visitor.getAttributes();
|
||||||
|
MetavoxelVisitation firstVisitation = { visitor, QVector<MetavoxelNode*>(attributes.size() + 1),
|
||||||
|
{ glm::vec3(), TOP_LEVEL_SIZE, QVector<AttributeValue>(attributes.size() + 1) } };
|
||||||
|
for (int i = 0; i < attributes.size(); i++) {
|
||||||
|
MetavoxelNode* node = _roots.value(attributes[i]);
|
||||||
|
firstVisitation.nodes[i] = node;
|
||||||
|
firstVisitation.info.attributeValues[i] = node ? node->getAttributeValue(attributes[i]) : attributes[i];
|
||||||
|
}
|
||||||
|
AttributePointer guideAttribute = AttributeRegistry::getInstance()->getGuideAttribute();
|
||||||
|
MetavoxelNode* node = _roots.value(guideAttribute);
|
||||||
|
firstVisitation.nodes.last() = node;
|
||||||
|
firstVisitation.info.attributeValues.last() = node ? node->getAttributeValue(guideAttribute) : guideAttribute;
|
||||||
|
static_cast<MetavoxelGuide*>(firstVisitation.info.attributeValues.last().getInlineValue<
|
||||||
|
PolymorphicDataPointer>().data())->guide(firstVisitation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelData::setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue) {
|
||||||
|
MetavoxelNode*& node = _roots[attributeValue.getAttribute()];
|
||||||
|
if (node == NULL) {
|
||||||
|
node = new MetavoxelNode(attributeValue.getAttribute());
|
||||||
|
}
|
||||||
|
if (node->setAttributeValue(path, 0, attributeValue) && attributeValue.isDefault()) {
|
||||||
|
node->destroy(attributeValue.getAttribute());
|
||||||
|
delete node;
|
||||||
|
_roots.remove(attributeValue.getAttribute());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeValue MetavoxelData::getAttributeValue(const MetavoxelPath& path, const AttributePointer& attribute) const {
|
||||||
|
MetavoxelNode* node = _roots.value(attribute);
|
||||||
|
if (node == NULL) {
|
||||||
|
return AttributeValue(attribute);
|
||||||
|
}
|
||||||
|
for (int i = 0, n = path.getSize(); i < n; i++) {
|
||||||
|
MetavoxelNode* child = node->getChild(path[i]);
|
||||||
|
if (child == NULL) {
|
||||||
|
return node->getAttributeValue(attribute);
|
||||||
|
}
|
||||||
|
node = child;
|
||||||
|
}
|
||||||
|
return node->getAttributeValue(attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) {
|
||||||
|
_attributeValue = attributeValue.copy();
|
||||||
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
_children[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetavoxelNode::setAttributeValue(const MetavoxelPath& path, int index, const AttributeValue& attributeValue) {
|
||||||
|
if (index == path.getSize()) {
|
||||||
|
setAttributeValue(attributeValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int element = path[index];
|
||||||
|
if (_children[element] == NULL) {
|
||||||
|
AttributeValue ownAttributeValue = getAttributeValue(attributeValue.getAttribute());
|
||||||
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
_children[i] = new MetavoxelNode(ownAttributeValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_children[element]->setAttributeValue(path, index + 1, attributeValue);
|
||||||
|
|
||||||
|
void* childValues[CHILD_COUNT];
|
||||||
|
bool allLeaves = true;
|
||||||
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
childValues[i] = _children[i]->_attributeValue;
|
||||||
|
allLeaves &= _children[i]->isLeaf();
|
||||||
|
}
|
||||||
|
if (attributeValue.getAttribute()->merge(_attributeValue, childValues) && allLeaves) {
|
||||||
|
clearChildren(attributeValue.getAttribute());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelNode::setAttributeValue(const AttributeValue& attributeValue) {
|
||||||
|
attributeValue.getAttribute()->destroy(_attributeValue);
|
||||||
|
_attributeValue = attributeValue.copy();
|
||||||
|
clearChildren(attributeValue.getAttribute());
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeValue MetavoxelNode::getAttributeValue(const AttributePointer& attribute) const {
|
||||||
|
return AttributeValue(attribute, _attributeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetavoxelNode::isLeaf() const {
|
||||||
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
if (_children[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelNode::destroy(const AttributePointer& attribute) {
|
||||||
|
attribute->destroy(_attributeValue);
|
||||||
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
if (_children[i]) {
|
||||||
|
_children[i]->destroy(attribute);
|
||||||
|
delete _children[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelNode::clearChildren(const AttributePointer& attribute) {
|
||||||
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
if (_children[i]) {
|
||||||
|
_children[i]->destroy(attribute);
|
||||||
|
delete _children[i];
|
||||||
|
_children[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MetavoxelPath::operator[](int index) const {
|
||||||
|
return _array.at(index * BITS_PER_ELEMENT) | (_array.at(index * BITS_PER_ELEMENT + 1) << 1) |
|
||||||
|
(_array.at(index * BITS_PER_ELEMENT + 2) << 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
MetavoxelPath& MetavoxelPath::operator+=(int element) {
|
||||||
|
int offset = _array.size();
|
||||||
|
_array.resize(offset + BITS_PER_ELEMENT);
|
||||||
|
_array.setBit(offset, element & 0x01);
|
||||||
|
_array.setBit(offset + 1, (element >> 1) & 0x01);
|
||||||
|
_array.setBit(offset + 2, element >> 2);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PolymorphicData* DefaultMetavoxelGuide::clone() const {
|
||||||
|
return new DefaultMetavoxelGuide();
|
||||||
|
}
|
||||||
|
|
||||||
|
const int X_MAXIMUM_FLAG = 1;
|
||||||
|
const int Y_MAXIMUM_FLAG = 2;
|
||||||
|
const int Z_MAXIMUM_FLAG = 4;
|
||||||
|
|
||||||
|
void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
||||||
|
visitation.info.isLeaf = visitation.allNodesLeaves();
|
||||||
|
if (!visitation.visitor.visit(visitation.info) || visitation.info.isLeaf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MetavoxelVisitation nextVisitation = { visitation.visitor, QVector<MetavoxelNode*>(visitation.nodes.size()),
|
||||||
|
{ glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.nodes.size()) } };
|
||||||
|
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
|
||||||
|
for (int j = 0; j < visitation.nodes.size(); j++) {
|
||||||
|
MetavoxelNode* node = visitation.nodes.at(j);
|
||||||
|
MetavoxelNode* child = node ? node->getChild(i) : NULL;
|
||||||
|
nextVisitation.info.attributeValues[j] = ((nextVisitation.nodes[j] = child)) ?
|
||||||
|
child->getAttributeValue(visitation.info.attributeValues[j].getAttribute()) :
|
||||||
|
visitation.info.attributeValues[j];
|
||||||
|
}
|
||||||
|
nextVisitation.info.minimum = visitation.info.minimum + glm::vec3(
|
||||||
|
(i & X_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f,
|
||||||
|
(i & Y_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f,
|
||||||
|
(i & Z_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f);
|
||||||
|
static_cast<MetavoxelGuide*>(nextVisitation.info.attributeValues.last().getInlineValue<
|
||||||
|
PolymorphicDataPointer>().data())->guide(nextVisitation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue ScriptedMetavoxelGuide::getAttributes(QScriptContext* context, QScriptEngine* engine) {
|
||||||
|
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
|
||||||
|
|
||||||
|
const QVector<AttributePointer>& attributes = guide->_visitation->visitor.getAttributes();
|
||||||
|
QScriptValue attributesValue = engine->newArray(attributes.size());
|
||||||
|
for (int i = 0; i < attributes.size(); i++) {
|
||||||
|
attributesValue.setProperty(i, engine->newQObject(attributes.at(i).data(), QScriptEngine::QtOwnership,
|
||||||
|
QScriptEngine::PreferExistingWrapperObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributesValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngine* engine) {
|
||||||
|
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
|
||||||
|
|
||||||
|
// start with the basics, including inherited attribute values
|
||||||
|
QScriptValue infoValue = context->argument(0);
|
||||||
|
QScriptValue minimum = infoValue.property(guide->_minimumHandle);
|
||||||
|
MetavoxelInfo info = {
|
||||||
|
glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()),
|
||||||
|
infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.attributeValues,
|
||||||
|
infoValue.property(guide->_isLeafHandle).toBool() };
|
||||||
|
|
||||||
|
// extract and convert the values provided by the script
|
||||||
|
QScriptValue attributeValues = infoValue.property(guide->_attributeValuesHandle);
|
||||||
|
const QVector<AttributePointer>& attributes = guide->_visitation->visitor.getAttributes();
|
||||||
|
for (int i = 0; i < attributes.size(); i++) {
|
||||||
|
QScriptValue attributeValue = attributeValues.property(i);
|
||||||
|
if (attributeValue.isValid()) {
|
||||||
|
info.attributeValues[i] = AttributeValue(attributes.at(i),
|
||||||
|
attributes.at(i)->createFromScript(attributeValue, engine));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue result = guide->_visitation->visitor.visit(info);
|
||||||
|
|
||||||
|
// destroy any created values
|
||||||
|
for (int i = 0; i < attributes.size(); i++) {
|
||||||
|
if (attributeValues.property(i).isValid()) {
|
||||||
|
info.attributeValues[i].getAttribute()->destroy(info.attributeValues[i].getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptedMetavoxelGuide::ScriptedMetavoxelGuide(const QScriptValue& guideFunction) :
|
||||||
|
_guideFunction(guideFunction),
|
||||||
|
_minimumHandle(guideFunction.engine()->toStringHandle("minimum")),
|
||||||
|
_sizeHandle(guideFunction.engine()->toStringHandle("size")),
|
||||||
|
_attributeValuesHandle(guideFunction.engine()->toStringHandle("attributeValues")),
|
||||||
|
_isLeafHandle(guideFunction.engine()->toStringHandle("isLeaf")),
|
||||||
|
_getAttributesFunction(guideFunction.engine()->newFunction(getAttributes, 0)),
|
||||||
|
_visitFunction(guideFunction.engine()->newFunction(visit, 1)),
|
||||||
|
_info(guideFunction.engine()->newObject()),
|
||||||
|
_minimum(guideFunction.engine()->newArray(3)) {
|
||||||
|
|
||||||
|
_arguments.append(guideFunction.engine()->newObject());
|
||||||
|
QScriptValue visitor = guideFunction.engine()->newObject();
|
||||||
|
visitor.setProperty("getAttributes", _getAttributesFunction);
|
||||||
|
visitor.setProperty("visit", _visitFunction);
|
||||||
|
_arguments[0].setProperty("visitor", visitor);
|
||||||
|
_arguments[0].setProperty("info", _info);
|
||||||
|
_info.setProperty(_minimumHandle, _minimum);
|
||||||
|
}
|
||||||
|
|
||||||
|
PolymorphicData* ScriptedMetavoxelGuide::clone() const {
|
||||||
|
return new ScriptedMetavoxelGuide(_guideFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
||||||
|
QScriptValue data = _guideFunction.engine()->newVariant(QVariant::fromValue<void*>(this));
|
||||||
|
_getAttributesFunction.setData(data);
|
||||||
|
_visitFunction.setData(data);
|
||||||
|
_minimum.setProperty(0, visitation.info.minimum.x);
|
||||||
|
_minimum.setProperty(1, visitation.info.minimum.y);
|
||||||
|
_minimum.setProperty(2, visitation.info.minimum.z);
|
||||||
|
_info.setProperty(_sizeHandle, visitation.info.size);
|
||||||
|
_info.setProperty(_isLeafHandle, visitation.info.isLeaf);
|
||||||
|
_visitation = &visitation;
|
||||||
|
_guideFunction.call(QScriptValue(), _arguments);
|
||||||
|
if (_guideFunction.engine()->hasUncaughtException()) {
|
||||||
|
qDebug() << "Script error: " << _guideFunction.engine()->uncaughtException().toString() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetavoxelVisitation::allNodesLeaves() const {
|
||||||
|
foreach (MetavoxelNode* node, nodes) {
|
||||||
|
if (node != NULL && !node->isLeaf()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
187
libraries/metavoxels/src/MetavoxelData.h
Normal file
187
libraries/metavoxels/src/MetavoxelData.h
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
//
|
||||||
|
// MetavoxelData.h
|
||||||
|
// metavoxels
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 12/6/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __interface__MetavoxelData__
|
||||||
|
#define __interface__MetavoxelData__
|
||||||
|
|
||||||
|
#include <QBitArray>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QScriptString>
|
||||||
|
#include <QScriptValue>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "AttributeRegistry.h"
|
||||||
|
|
||||||
|
class QScriptContext;
|
||||||
|
|
||||||
|
class MetavoxelNode;
|
||||||
|
class MetavoxelPath;
|
||||||
|
class MetavoxelVisitation;
|
||||||
|
class MetavoxelVisitor;
|
||||||
|
|
||||||
|
/// The base metavoxel representation shared between server and client.
|
||||||
|
class MetavoxelData {
|
||||||
|
public:
|
||||||
|
|
||||||
|
~MetavoxelData();
|
||||||
|
|
||||||
|
/// Applies the specified visitor to the contained voxels.
|
||||||
|
void guide(MetavoxelVisitor& visitor);
|
||||||
|
|
||||||
|
/// Sets the attribute value corresponding to the specified path.
|
||||||
|
void setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue);
|
||||||
|
|
||||||
|
/// Retrieves the attribute value corresponding to the specified path.
|
||||||
|
AttributeValue getAttributeValue(const MetavoxelPath& path, const AttributePointer& attribute) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QHash<AttributePointer, MetavoxelNode*> _roots;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A single node within a metavoxel layer.
|
||||||
|
class MetavoxelNode {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const int CHILD_COUNT = 8;
|
||||||
|
|
||||||
|
MetavoxelNode(const AttributeValue& attributeValue);
|
||||||
|
|
||||||
|
/// Descends the voxel tree in order to set the value of a node.
|
||||||
|
/// \param path the path to follow
|
||||||
|
/// \param index the position in the path
|
||||||
|
/// \return whether or not the node is entirely equal to the value
|
||||||
|
bool setAttributeValue(const MetavoxelPath& path, int index, const AttributeValue& attributeValue);
|
||||||
|
|
||||||
|
void setAttributeValue(const AttributeValue& attributeValue);
|
||||||
|
|
||||||
|
AttributeValue getAttributeValue(const AttributePointer& attribute) const;
|
||||||
|
|
||||||
|
MetavoxelNode* getChild(int index) const { return _children[index]; }
|
||||||
|
void setChild(int index, MetavoxelNode* child) { _children[index] = child; }
|
||||||
|
|
||||||
|
bool isLeaf() const;
|
||||||
|
|
||||||
|
void destroy(const AttributePointer& attribute);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(MetavoxelNode)
|
||||||
|
|
||||||
|
void clearChildren(const AttributePointer& attribute);
|
||||||
|
|
||||||
|
void* _attributeValue;
|
||||||
|
MetavoxelNode* _children[CHILD_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A path down an octree.
|
||||||
|
class MetavoxelPath {
|
||||||
|
public:
|
||||||
|
|
||||||
|
int getSize() const { return _array.size() / BITS_PER_ELEMENT; }
|
||||||
|
bool isEmpty() const { return _array.isEmpty(); }
|
||||||
|
|
||||||
|
int operator[](int index) const;
|
||||||
|
|
||||||
|
MetavoxelPath& operator+=(int element);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static const int BITS_PER_ELEMENT = 3;
|
||||||
|
|
||||||
|
QBitArray _array;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Contains information about a metavoxel (explicit or procedural).
|
||||||
|
class MetavoxelInfo {
|
||||||
|
public:
|
||||||
|
|
||||||
|
glm::vec3 minimum; ///< the minimum extent of the area covered by the voxel
|
||||||
|
float size; ///< the size of the voxel in all dimensions
|
||||||
|
QVector<AttributeValue> attributeValues;
|
||||||
|
bool isLeaf;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Interface for visitors to metavoxels.
|
||||||
|
class MetavoxelVisitor {
|
||||||
|
public:
|
||||||
|
|
||||||
|
MetavoxelVisitor(const QVector<AttributePointer>& attributes) : _attributes(attributes) { }
|
||||||
|
|
||||||
|
/// Returns a reference to the list of attributes desired.
|
||||||
|
const QVector<AttributePointer>& getAttributes() const { return _attributes; }
|
||||||
|
|
||||||
|
/// Visits a metavoxel.
|
||||||
|
/// \param info the metavoxel ata
|
||||||
|
/// \param if true, continue descending; if false, stop
|
||||||
|
virtual bool visit(const MetavoxelInfo& info) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
QVector<AttributePointer> _attributes;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Interface for objects that guide metavoxel visitors.
|
||||||
|
class MetavoxelGuide : public PolymorphicData {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Guides the specified visitor to the contained voxels.
|
||||||
|
virtual void guide(MetavoxelVisitation& visitation) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Guides visitors through the explicit content of the system.
|
||||||
|
class DefaultMetavoxelGuide : public MetavoxelGuide {
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual PolymorphicData* clone() const;
|
||||||
|
|
||||||
|
virtual void guide(MetavoxelVisitation& visitation);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Represents a guide implemented in Javascript.
|
||||||
|
class ScriptedMetavoxelGuide : public MetavoxelGuide {
|
||||||
|
public:
|
||||||
|
|
||||||
|
ScriptedMetavoxelGuide(const QScriptValue& guideFunction);
|
||||||
|
|
||||||
|
virtual PolymorphicData* clone() const;
|
||||||
|
|
||||||
|
virtual void guide(MetavoxelVisitation& visitation);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static QScriptValue getAttributes(QScriptContext* context, QScriptEngine* engine);
|
||||||
|
static QScriptValue visit(QScriptContext* context, QScriptEngine* engine);
|
||||||
|
|
||||||
|
QScriptValue _guideFunction;
|
||||||
|
QScriptString _minimumHandle;
|
||||||
|
QScriptString _sizeHandle;
|
||||||
|
QScriptString _attributeValuesHandle;
|
||||||
|
QScriptString _isLeafHandle;
|
||||||
|
QScriptValueList _arguments;
|
||||||
|
QScriptValue _getAttributesFunction;
|
||||||
|
QScriptValue _visitFunction;
|
||||||
|
QScriptValue _info;
|
||||||
|
QScriptValue _minimum;
|
||||||
|
|
||||||
|
MetavoxelVisitation* _visitation;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Contains the state associated with a visit to a metavoxel system.
|
||||||
|
class MetavoxelVisitation {
|
||||||
|
public:
|
||||||
|
|
||||||
|
MetavoxelVisitor& visitor;
|
||||||
|
QVector<MetavoxelNode*> nodes;
|
||||||
|
MetavoxelInfo info;
|
||||||
|
|
||||||
|
bool allNodesLeaves() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__interface__MetavoxelData__) */
|
|
@ -656,6 +656,17 @@ void OctreeServer::run() {
|
||||||
_persistThread->initialize(true);
|
_persistThread->initialize(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug option to demonstrate that the server's local time does not
|
||||||
|
// need to be in sync with any other network node. This forces clock
|
||||||
|
// skew for the individual server node
|
||||||
|
const char* CLOCK_SKEW = "--clockSkew";
|
||||||
|
const char* clockSkewOption = getCmdOption(_argc, _argv, CLOCK_SKEW);
|
||||||
|
if (clockSkewOption) {
|
||||||
|
int clockSkew = atoi(clockSkewOption);
|
||||||
|
usecTimestampNowForceClockSkew(clockSkew);
|
||||||
|
qDebug("clockSkewOption=%s clockSkew=%d\n", clockSkewOption, clockSkew);
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see if the user passed in a command line option for setting packet send rate
|
// Check to see if the user passed in a command line option for setting packet send rate
|
||||||
const char* PACKETS_PER_SECOND = "--packetsPerSecond";
|
const char* PACKETS_PER_SECOND = "--packetsPerSecond";
|
||||||
|
|
|
@ -36,15 +36,16 @@ Particle::~Particle() {
|
||||||
void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity,
|
void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity,
|
||||||
float damping, bool inHand, QString updateScript, uint32_t id) {
|
float damping, bool inHand, QString updateScript, uint32_t id) {
|
||||||
if (id == NEW_PARTICLE) {
|
if (id == NEW_PARTICLE) {
|
||||||
_created = usecTimestampNow();
|
|
||||||
_id = _nextID;
|
_id = _nextID;
|
||||||
_nextID++;
|
_nextID++;
|
||||||
} else {
|
} else {
|
||||||
_id = id;
|
_id = id;
|
||||||
}
|
}
|
||||||
_lastUpdated = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
_lastEdited = _lastUpdated;
|
_edited = now;
|
||||||
|
_lastSimulated = now;
|
||||||
|
_created = now; // will get updated as appropriate in setLifetime()
|
||||||
|
|
||||||
_position = position;
|
_position = position;
|
||||||
_radius = radius;
|
_radius = radius;
|
||||||
memcpy(_color, color, sizeof(_color));
|
memcpy(_color, color, sizeof(_color));
|
||||||
|
@ -63,13 +64,10 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
|
||||||
//printf("Particle::appendParticleData()... getID()=%d\n", getID());
|
//printf("Particle::appendParticleData()... getID()=%d\n", getID());
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
success = packetData->appendValue(getCreated());
|
success = packetData->appendValue(getLifetime());
|
||||||
}
|
}
|
||||||
if (success) {
|
if (success) {
|
||||||
success = packetData->appendValue(getLastUpdated());
|
success = packetData->appendValue(getEditedAgo());
|
||||||
}
|
|
||||||
if (success) {
|
|
||||||
success = packetData->appendValue(getLastEdited());
|
|
||||||
}
|
}
|
||||||
if (success) {
|
if (success) {
|
||||||
success = packetData->appendValue(getRadius());
|
success = packetData->appendValue(getRadius());
|
||||||
|
@ -103,9 +101,30 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Particle::expectedBytes() {
|
int Particle::expectedBytes() {
|
||||||
int expectedBytes = sizeof(uint32_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(float) +
|
int expectedBytes = sizeof(uint32_t) // id
|
||||||
sizeof(glm::vec3) + sizeof(rgbColor) + sizeof(glm::vec3) +
|
+ sizeof(float) // lifetime
|
||||||
sizeof(glm::vec3) + sizeof(float) + sizeof(bool);
|
+ sizeof(float) // edited ago
|
||||||
|
+ sizeof(float) // radius
|
||||||
|
+ sizeof(glm::vec3) // position
|
||||||
|
+ sizeof(rgbColor) // color
|
||||||
|
+ sizeof(glm::vec3) // velocity
|
||||||
|
+ sizeof(glm::vec3) // gravity
|
||||||
|
+ sizeof(float) // damping
|
||||||
|
+ sizeof(bool); // inhand
|
||||||
|
// potentially more...
|
||||||
|
return expectedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Particle::expectedEditMessageBytes() {
|
||||||
|
int expectedBytes = sizeof(uint32_t) // id
|
||||||
|
+ sizeof(float) // radius
|
||||||
|
+ sizeof(glm::vec3) // position
|
||||||
|
+ sizeof(rgbColor) // color
|
||||||
|
+ sizeof(glm::vec3) // velocity
|
||||||
|
+ sizeof(glm::vec3) // gravity
|
||||||
|
+ sizeof(float) // damping
|
||||||
|
+ sizeof(bool); // inhand
|
||||||
|
// potentially more...
|
||||||
return expectedBytes;
|
return expectedBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,20 +138,19 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
dataAt += sizeof(_id);
|
dataAt += sizeof(_id);
|
||||||
bytesRead += sizeof(_id);
|
bytesRead += sizeof(_id);
|
||||||
|
|
||||||
// created
|
// lifetime
|
||||||
memcpy(&_created, dataAt, sizeof(_created));
|
float lifetime;
|
||||||
dataAt += sizeof(_created);
|
memcpy(&lifetime, dataAt, sizeof(lifetime));
|
||||||
bytesRead += sizeof(_created);
|
dataAt += sizeof(lifetime);
|
||||||
|
bytesRead += sizeof(lifetime);
|
||||||
|
setLifetime(lifetime);
|
||||||
|
|
||||||
// lastupdated
|
// edited ago
|
||||||
memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated));
|
float editedAgo;
|
||||||
dataAt += sizeof(_lastUpdated);
|
memcpy(&editedAgo, dataAt, sizeof(editedAgo));
|
||||||
bytesRead += sizeof(_lastUpdated);
|
dataAt += sizeof(editedAgo);
|
||||||
|
bytesRead += sizeof(editedAgo);
|
||||||
// _lastEdited
|
setEditedAgo(editedAgo);
|
||||||
memcpy(&_lastEdited, dataAt, sizeof(_lastEdited));
|
|
||||||
dataAt += sizeof(_lastEdited);
|
|
||||||
bytesRead += sizeof(_lastEdited);
|
|
||||||
|
|
||||||
// radius
|
// radius
|
||||||
memcpy(&_radius, dataAt, sizeof(_radius));
|
memcpy(&_radius, dataAt, sizeof(_radius));
|
||||||
|
@ -186,7 +204,7 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
|
|
||||||
|
|
||||||
Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes) {
|
Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes) {
|
||||||
Particle newParticle; // id and lastUpdated will get set here...
|
Particle newParticle; // id and _lastSimulated will get set here...
|
||||||
unsigned char* dataAt = data;
|
unsigned char* dataAt = data;
|
||||||
processedBytes = 0;
|
processedBytes = 0;
|
||||||
|
|
||||||
|
@ -214,26 +232,17 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
||||||
processedBytes += sizeof(creatorTokenID);
|
processedBytes += sizeof(creatorTokenID);
|
||||||
newParticle.setCreatorTokenID(creatorTokenID);
|
newParticle.setCreatorTokenID(creatorTokenID);
|
||||||
newParticle._newlyCreated = true;
|
newParticle._newlyCreated = true;
|
||||||
|
|
||||||
|
newParticle.setLifetime(0); // this guy is new!
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newParticle._id = editID;
|
newParticle._id = editID;
|
||||||
newParticle._newlyCreated = false;
|
newParticle._newlyCreated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// created
|
// clearly we just edited it
|
||||||
memcpy(&newParticle._created, dataAt, sizeof(newParticle._created));
|
newParticle.setEditedAgo(0);
|
||||||
dataAt += sizeof(newParticle._created);
|
|
||||||
processedBytes += sizeof(newParticle._created);
|
|
||||||
|
|
||||||
// lastUpdated
|
|
||||||
memcpy(&newParticle._lastUpdated, dataAt, sizeof(newParticle._lastUpdated));
|
|
||||||
dataAt += sizeof(newParticle._lastUpdated);
|
|
||||||
processedBytes += sizeof(newParticle._lastUpdated);
|
|
||||||
|
|
||||||
// lastEdited
|
|
||||||
memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited));
|
|
||||||
dataAt += sizeof(newParticle._lastEdited);
|
|
||||||
processedBytes += sizeof(newParticle._lastEdited);
|
|
||||||
|
|
||||||
// radius
|
// radius
|
||||||
memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius));
|
memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius));
|
||||||
dataAt += sizeof(newParticle._radius);
|
dataAt += sizeof(newParticle._radius);
|
||||||
|
@ -291,9 +300,8 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
||||||
|
|
||||||
void Particle::debugDump() const {
|
void Particle::debugDump() const {
|
||||||
printf("Particle id :%u\n", _id);
|
printf("Particle id :%u\n", _id);
|
||||||
printf(" created:%llu\n", _created);
|
printf(" lifetime:%f\n", getLifetime());
|
||||||
printf(" last updated:%llu\n", _lastUpdated);
|
printf(" edited ago:%f\n", getEditedAgo());
|
||||||
printf(" last edited:%llu\n", _lastEdited);
|
|
||||||
printf(" position:%f,%f,%f\n", _position.x, _position.y, _position.z);
|
printf(" position:%f,%f,%f\n", _position.x, _position.y, _position.z);
|
||||||
printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z);
|
printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z);
|
||||||
printf(" gravity:%f,%f,%f\n", _gravity.x, _gravity.y, _gravity.z);
|
printf(" gravity:%f,%f,%f\n", _gravity.x, _gravity.y, _gravity.z);
|
||||||
|
@ -313,7 +321,7 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
|
||||||
|
|
||||||
int octets = numberOfThreeBitSectionsInCode(octcode);
|
int octets = numberOfThreeBitSectionsInCode(octcode);
|
||||||
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
|
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
|
||||||
int lenfthOfEditData = lengthOfOctcode + expectedBytes();
|
int lenfthOfEditData = lengthOfOctcode + expectedEditMessageBytes();
|
||||||
|
|
||||||
// make sure we have room to copy this particle
|
// make sure we have room to copy this particle
|
||||||
if (sizeOut + lenfthOfEditData > sizeIn) {
|
if (sizeOut + lenfthOfEditData > sizeIn) {
|
||||||
|
@ -325,7 +333,6 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
|
||||||
sizeOut += lengthOfOctcode;
|
sizeOut += lengthOfOctcode;
|
||||||
|
|
||||||
// Now add our edit content details...
|
// Now add our edit content details...
|
||||||
uint64_t created = usecTimestampNow();
|
|
||||||
|
|
||||||
// id
|
// id
|
||||||
memcpy(copyAt, &details[i].id, sizeof(details[i].id));
|
memcpy(copyAt, &details[i].id, sizeof(details[i].id));
|
||||||
|
@ -338,25 +345,8 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
|
||||||
memcpy(copyAt, &details[i].creatorTokenID, sizeof(details[i].creatorTokenID));
|
memcpy(copyAt, &details[i].creatorTokenID, sizeof(details[i].creatorTokenID));
|
||||||
copyAt += sizeof(details[i].creatorTokenID);
|
copyAt += sizeof(details[i].creatorTokenID);
|
||||||
sizeOut += sizeof(details[i].creatorTokenID);
|
sizeOut += sizeof(details[i].creatorTokenID);
|
||||||
} else {
|
|
||||||
created = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// created
|
|
||||||
memcpy(copyAt, &created, sizeof(created));
|
|
||||||
copyAt += sizeof(created);
|
|
||||||
sizeOut += sizeof(created);
|
|
||||||
|
|
||||||
// lastUpdated
|
|
||||||
memcpy(copyAt, &details[i].lastUpdated, sizeof(details[i].lastUpdated));
|
|
||||||
copyAt += sizeof(details[i].lastUpdated);
|
|
||||||
sizeOut += sizeof(details[i].lastUpdated);
|
|
||||||
|
|
||||||
// lastEdited
|
|
||||||
memcpy(copyAt, &details[i].lastEdited, sizeof(details[i].lastEdited));
|
|
||||||
copyAt += sizeof(details[i].lastEdited);
|
|
||||||
sizeOut += sizeof(details[i].lastEdited);
|
|
||||||
|
|
||||||
// radius
|
// radius
|
||||||
memcpy(copyAt, &details[i].radius, sizeof(details[i].radius));
|
memcpy(copyAt, &details[i].radius, sizeof(details[i].radius));
|
||||||
copyAt += sizeof(details[i].radius);
|
copyAt += sizeof(details[i].radius);
|
||||||
|
@ -405,7 +395,6 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
|
||||||
if (wantDebugging) {
|
if (wantDebugging) {
|
||||||
printf("encodeParticleEditMessageDetails()....\n");
|
printf("encodeParticleEditMessageDetails()....\n");
|
||||||
printf("Particle id :%u\n", details[i].id);
|
printf("Particle id :%u\n", details[i].id);
|
||||||
printf(" last updated:%llu\n", details[i].lastUpdated);
|
|
||||||
printf(" nextID:%u\n", _nextID);
|
printf(" nextID:%u\n", _nextID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,21 +407,30 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
|
||||||
|
|
||||||
|
|
||||||
void Particle::update() {
|
void Particle::update() {
|
||||||
|
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
uint64_t elapsed = now - _lastUpdated;
|
uint64_t elapsed = now - _lastSimulated;
|
||||||
uint64_t USECS_PER_SECOND = 1000 * 1000;
|
|
||||||
float timeElapsed = (float)((float)elapsed/(float)USECS_PER_SECOND);
|
float timeElapsed = (float)((float)elapsed/(float)USECS_PER_SECOND);
|
||||||
|
|
||||||
|
|
||||||
// calculate our default shouldDie state... then allow script to change it if it wants...
|
// calculate our default shouldDie state... then allow script to change it if it wants...
|
||||||
float velocityScalar = glm::length(getVelocity());
|
float velocityScalar = glm::length(getVelocity());
|
||||||
const float STILL_MOVING = 0.05 / TREE_SCALE;
|
const float STILL_MOVING = 0.05 / TREE_SCALE;
|
||||||
bool isStillMoving = (velocityScalar > STILL_MOVING);
|
bool isStillMoving = (velocityScalar > STILL_MOVING);
|
||||||
const uint64_t REALLY_OLD = 30 * 1000 * 1000;
|
const float REALLY_OLD = 30.0f; // 30 seconds
|
||||||
bool isReallyOld = (getLifetime() > REALLY_OLD);
|
bool isReallyOld = (getLifetime() > REALLY_OLD);
|
||||||
bool isInHand = getInHand();
|
bool isInHand = getInHand();
|
||||||
bool shouldDie = !isInHand && !isStillMoving && isReallyOld;
|
bool shouldDie = !isInHand && !isStillMoving && isReallyOld;
|
||||||
setShouldDie(shouldDie);
|
setShouldDie(shouldDie);
|
||||||
|
|
||||||
|
bool wantDebug = false;
|
||||||
|
if (wantDebug) {
|
||||||
|
printf("Particle::update()... timeElapsed: %f lifeTime:%f editedAgo:%f "
|
||||||
|
"isInHand:%s isStillMoveing:%s isReallyOld:%s shouldDie:%s\n",
|
||||||
|
timeElapsed, getLifetime(), getEditedAgo(), debug::valueOf(isInHand), debug::valueOf(isStillMoving),
|
||||||
|
debug::valueOf(isReallyOld), debug::valueOf(shouldDie));
|
||||||
|
}
|
||||||
|
|
||||||
runScript(); // allow the javascript to alter our state
|
runScript(); // allow the javascript to alter our state
|
||||||
|
|
||||||
// If the ball is in hand, it doesn't move or have gravity effect it
|
// If the ball is in hand, it doesn't move or have gravity effect it
|
||||||
|
@ -454,7 +452,7 @@ void Particle::update() {
|
||||||
//printf("applying damping to Particle timeElapsed=%f\n",timeElapsed);
|
//printf("applying damping to Particle timeElapsed=%f\n",timeElapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastUpdated = now;
|
_lastSimulated = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Particle::runScript() {
|
void Particle::runScript() {
|
||||||
|
@ -484,3 +482,19 @@ void Particle::runScript() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Particle::setLifetime(float lifetime) {
|
||||||
|
uint64_t lifetimeInUsecs = lifetime * USECS_PER_SECOND;
|
||||||
|
_created = usecTimestampNow() - lifetimeInUsecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particle::setEditedAgo(float editedAgo) {
|
||||||
|
uint64_t editedAgoInUsecs = editedAgo * USECS_PER_SECOND;
|
||||||
|
_edited = usecTimestampNow() - editedAgoInUsecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particle::copyChangedProperties(const Particle& other) {
|
||||||
|
float lifetime = getLifetime();
|
||||||
|
*this = other;
|
||||||
|
setLifetime(lifetime);
|
||||||
|
}
|
||||||
|
|
|
@ -25,8 +25,6 @@ const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF;
|
||||||
class ParticleDetail {
|
class ParticleDetail {
|
||||||
public:
|
public:
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint64_t lastUpdated;
|
|
||||||
uint64_t lastEdited;
|
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
float radius;
|
float radius;
|
||||||
rgbColor color;
|
rgbColor color;
|
||||||
|
@ -68,10 +66,11 @@ public:
|
||||||
const glm::vec3& getGravity() const { return _gravity; }
|
const glm::vec3& getGravity() const { return _gravity; }
|
||||||
bool getInHand() const { return _inHand; }
|
bool getInHand() const { return _inHand; }
|
||||||
float getDamping() const { return _damping; }
|
float getDamping() const { return _damping; }
|
||||||
uint64_t getCreated() const { return _created; }
|
|
||||||
uint64_t getLifetime() const { return usecTimestampNow() - _created; }
|
/// lifetime of the particle in seconds
|
||||||
uint64_t getLastUpdated() const { return _lastUpdated; }
|
float getLifetime() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
|
||||||
uint64_t getLastEdited() const { return _lastEdited; }
|
/// seconds since last edited
|
||||||
|
float getEditedAgo() const { return (float)(usecTimestampNow() - _edited) / (float)USECS_PER_SECOND; }
|
||||||
uint32_t getID() const { return _id; }
|
uint32_t getID() const { return _id; }
|
||||||
bool getShouldDie() const { return _shouldDie; }
|
bool getShouldDie() const { return _shouldDie; }
|
||||||
QString getUpdateScript() const { return _updateScript; }
|
QString getUpdateScript() const { return _updateScript; }
|
||||||
|
@ -93,11 +92,11 @@ public:
|
||||||
void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; }
|
void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; }
|
||||||
void setUpdateScript(QString updateScript) { _updateScript = updateScript; }
|
void setUpdateScript(QString updateScript) { _updateScript = updateScript; }
|
||||||
void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; }
|
void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; }
|
||||||
void setCreated(uint64_t created) { _created = created; }
|
|
||||||
|
|
||||||
bool appendParticleData(OctreePacketData* packetData) const;
|
bool appendParticleData(OctreePacketData* packetData) const;
|
||||||
int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
||||||
static int expectedBytes();
|
static int expectedBytes();
|
||||||
|
static int expectedEditMessageBytes();
|
||||||
|
|
||||||
static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details,
|
static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details,
|
||||||
unsigned char* bufferOut, int sizeIn, int& sizeOut);
|
unsigned char* bufferOut, int sizeIn, int& sizeOut);
|
||||||
|
@ -105,20 +104,24 @@ public:
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
void debugDump() const;
|
void debugDump() const;
|
||||||
|
|
||||||
|
// similar to assignment/copy, but it handles keeping lifetime accurate
|
||||||
|
void copyChangedProperties(const Particle& other);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void runScript();
|
void runScript();
|
||||||
static QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3);
|
static QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3);
|
||||||
static void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3);
|
static void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3);
|
||||||
static QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color);
|
static QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color);
|
||||||
static void xColorFromScriptValue(const QScriptValue &object, xColor& color);
|
static void xColorFromScriptValue(const QScriptValue &object, xColor& color);
|
||||||
|
|
||||||
|
void setLifetime(float lifetime);
|
||||||
|
void setEditedAgo(float editedAgo);
|
||||||
|
|
||||||
glm::vec3 _position;
|
glm::vec3 _position;
|
||||||
rgbColor _color;
|
rgbColor _color;
|
||||||
float _radius;
|
float _radius;
|
||||||
glm::vec3 _velocity;
|
glm::vec3 _velocity;
|
||||||
uint64_t _lastUpdated;
|
|
||||||
uint64_t _created;
|
|
||||||
uint64_t _lastEdited;
|
|
||||||
uint32_t _id;
|
uint32_t _id;
|
||||||
static uint32_t _nextID;
|
static uint32_t _nextID;
|
||||||
bool _shouldDie;
|
bool _shouldDie;
|
||||||
|
@ -129,6 +132,12 @@ protected:
|
||||||
|
|
||||||
uint32_t _creatorTokenID;
|
uint32_t _creatorTokenID;
|
||||||
bool _newlyCreated;
|
bool _newlyCreated;
|
||||||
|
|
||||||
|
// these are never included in wire time
|
||||||
|
uint64_t _lastSimulated;
|
||||||
|
uint64_t _created;
|
||||||
|
uint64_t _edited;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParticleScriptObject : public QObject {
|
class ParticleScriptObject : public QObject {
|
||||||
|
@ -144,9 +153,7 @@ public slots:
|
||||||
float getDamping() const { return _particle->getDamping(); }
|
float getDamping() const { return _particle->getDamping(); }
|
||||||
float getRadius() const { return _particle->getRadius(); }
|
float getRadius() const { return _particle->getRadius(); }
|
||||||
bool getShouldDie() { return _particle->getShouldDie(); }
|
bool getShouldDie() { return _particle->getShouldDie(); }
|
||||||
float getCreated() const { return ((float)_particle->getCreated() / (float)USECS_PER_SECOND); }
|
float getLifetime() const { return _particle->getLifetime(); }
|
||||||
float getLifetime() const { return ((float)_particle->getLifetime() / (float)USECS_PER_SECOND); }
|
|
||||||
|
|
||||||
|
|
||||||
void setPosition(glm::vec3 value) { _particle->setPosition(value); }
|
void setPosition(glm::vec3 value) { _particle->setPosition(value); }
|
||||||
void setVelocity(glm::vec3 value) { _particle->setVelocity(value); }
|
void setVelocity(glm::vec3 value) { _particle->setVelocity(value); }
|
||||||
|
|
|
@ -206,7 +206,7 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::
|
||||||
void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency) {
|
void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency) {
|
||||||
|
|
||||||
// consider whether to have the collision make a sound
|
// consider whether to have the collision make a sound
|
||||||
const float AUDIBLE_COLLISION_THRESHOLD = 0.02f;
|
const float AUDIBLE_COLLISION_THRESHOLD = 0.1f;
|
||||||
const float COLLISION_LOUDNESS = 1.f;
|
const float COLLISION_LOUDNESS = 1.f;
|
||||||
const float DURATION_SCALING = 0.004f;
|
const float DURATION_SCALING = 0.004f;
|
||||||
const float NOISE_SCALING = 0.1f;
|
const float NOISE_SCALING = 0.1f;
|
||||||
|
@ -235,6 +235,6 @@ void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm
|
||||||
fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f),
|
fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f),
|
||||||
frequency * (1.f + velocityTangentToCollision / velocityTowardCollision),
|
frequency * (1.f + velocityTangentToCollision / velocityTowardCollision),
|
||||||
fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f),
|
fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f),
|
||||||
1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision, true);
|
1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -44,8 +44,7 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor
|
||||||
glm::vec3 gravity, float damping, bool inHand, QString updateScript) {
|
glm::vec3 gravity, float damping, bool inHand, QString updateScript) {
|
||||||
|
|
||||||
// setup a ParticleDetail struct with the data
|
// setup a ParticleDetail struct with the data
|
||||||
uint64_t now = usecTimestampNow();
|
ParticleDetail addParticleDetail = { NEW_PARTICLE,
|
||||||
ParticleDetail addParticleDetail = { NEW_PARTICLE, now, now,
|
|
||||||
position, radius, {color.red, color.green, color.blue },
|
position, radius, {color.red, color.green, color.blue },
|
||||||
velocity, gravity, damping, inHand, updateScript, _creatorTokenID };
|
velocity, gravity, damping, inHand, updateScript, _creatorTokenID };
|
||||||
|
|
||||||
|
@ -70,8 +69,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup a ParticleDetail struct with the data
|
// setup a ParticleDetail struct with the data
|
||||||
uint64_t now = usecTimestampNow();
|
ParticleDetail newParticleDetail = { _id,
|
||||||
ParticleDetail newParticleDetail = { _id, now, now,
|
|
||||||
position, radius, {color.red, color.green, color.blue },
|
position, radius, {color.red, color.green, color.blue },
|
||||||
velocity, gravity, damping, inHand, updateScript, _creatorTokenID };
|
velocity, gravity, damping, inHand, updateScript, _creatorTokenID };
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,7 @@ unsigned int ParticleScriptingInterface::queueParticleAdd(glm::vec3 position, fl
|
||||||
_nextCreatorTokenID++;
|
_nextCreatorTokenID++;
|
||||||
|
|
||||||
// setup a ParticleDetail struct with the data
|
// setup a ParticleDetail struct with the data
|
||||||
uint64_t now = usecTimestampNow();
|
ParticleDetail addParticleDetail = { NEW_PARTICLE,
|
||||||
ParticleDetail addParticleDetail = { NEW_PARTICLE, now, now,
|
|
||||||
position, radius, {color.red, color.green, color.blue }, velocity,
|
position, radius, {color.red, color.green, color.blue }, velocity,
|
||||||
gravity, damping, inHand, updateScript, creatorTokenID };
|
gravity, damping, inHand, updateScript, creatorTokenID };
|
||||||
|
|
||||||
|
|
|
@ -119,33 +119,19 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) {
|
||||||
uint16_t numberOfParticles = _particles.size();
|
uint16_t numberOfParticles = _particles.size();
|
||||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||||
if (_particles[i].getID() == particle.getID()) {
|
if (_particles[i].getID() == particle.getID()) {
|
||||||
int difference = _particles[i].getLastUpdated() - particle.getLastUpdated();
|
bool changedOnServer = _particles[i].getEditedAgo() > particle.getEditedAgo();
|
||||||
|
if (changedOnServer) {
|
||||||
bool changedOnServer = _particles[i].getLastEdited() < particle.getLastEdited();
|
|
||||||
bool localOlder = _particles[i].getLastUpdated() < particle.getLastUpdated();
|
|
||||||
|
|
||||||
if (changedOnServer || localOlder) {
|
|
||||||
|
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
printf("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n",
|
printf("local particle [id:%d] %s, particle.isNewlyCreated()=%s\n",
|
||||||
particle.getID(), (changedOnServer ? "CHANGED" : "same"),
|
particle.getID(), (changedOnServer ? "CHANGED" : "same"),
|
||||||
(localOlder ? "OLDER" : "NEWER"),
|
debug::valueOf(particle.isNewlyCreated()) );
|
||||||
difference, debug::valueOf(particle.isNewlyCreated()) );
|
|
||||||
}
|
}
|
||||||
|
_particles[i].copyChangedProperties(particle);
|
||||||
uint64_t actuallyCreated = particle.getCreated();
|
|
||||||
if (!particle.isNewlyCreated()) {
|
|
||||||
actuallyCreated = _particles[i].getCreated();
|
|
||||||
}
|
|
||||||
_particles[i] = particle;
|
|
||||||
_particles[i].setCreated(actuallyCreated);
|
|
||||||
} else {
|
} else {
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
printf(">>> NO CHANGE <<< -- local particle [id:%d] %s and %s than server particle by %d, "
|
printf(">>> NO CHANGE <<< -- local particle [id:%d] %s particle.isNewlyCreated()=%s\n",
|
||||||
"particle.isNewlyCreated()=%s\n",
|
|
||||||
particle.getID(), (changedOnServer ? "CHANGED" : "same"),
|
particle.getID(), (changedOnServer ? "CHANGED" : "same"),
|
||||||
(localOlder ? "OLDER" : "NEWER"),
|
debug::valueOf(particle.isNewlyCreated()) );
|
||||||
difference, debug::valueOf(particle.isNewlyCreated()) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -6,7 +6,7 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||||
# setup for find modules
|
# setup for find modules
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||||
|
|
||||||
set(TARGET_NAME scriptengine)
|
set(TARGET_NAME script-engine)
|
||||||
|
|
||||||
find_package(Qt5Widgets REQUIRED)
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// AbstractControllerScriptingInterface.h
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 12/17/13
|
||||||
|
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __hifi__AbstractControllerScriptingInterface__
|
||||||
|
#define __hifi__AbstractControllerScriptingInterface__
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
/// handles scripting of input controller commands from JS
|
||||||
|
class AbstractControllerScriptingInterface : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual bool isPrimaryButtonPressed() const = 0;
|
||||||
|
virtual glm::vec2 getPrimaryJoystickPosition() const = 0;
|
||||||
|
|
||||||
|
virtual int getNumberOfButtons() const = 0;
|
||||||
|
virtual bool isButtonPressed(int buttonIndex) const = 0;
|
||||||
|
|
||||||
|
virtual int getNumberOfTriggers() const = 0;
|
||||||
|
virtual float getTriggerValue(int triggerIndex) const = 0;
|
||||||
|
|
||||||
|
virtual int getNumberOfJoysticks() const = 0;
|
||||||
|
virtual glm::vec2 getJoystickPosition(int joystickIndex) const = 0;
|
||||||
|
|
||||||
|
virtual int getNumberOfSpatialControls() const = 0;
|
||||||
|
virtual glm::vec3 getSpatialControlPosition(int controlIndex) const = 0;
|
||||||
|
virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const = 0;
|
||||||
|
virtual glm::vec3 getSpatialControlNormal(int controlIndex) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__hifi__AbstractControllerScriptingInterface__) */
|
|
@ -24,10 +24,14 @@
|
||||||
|
|
||||||
int ScriptEngine::_scriptNumber = 1;
|
int ScriptEngine::_scriptNumber = 1;
|
||||||
|
|
||||||
ScriptEngine::ScriptEngine(QString scriptContents, bool wantMenuItems,
|
ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems,
|
||||||
const char* scriptMenuName, AbstractMenuInterface* menu) {
|
const char* scriptMenuName, AbstractMenuInterface* menu,
|
||||||
|
AbstractControllerScriptingInterface* controllerScriptingInterface) {
|
||||||
_scriptContents = scriptContents;
|
_scriptContents = scriptContents;
|
||||||
_isFinished = false;
|
_isFinished = false;
|
||||||
|
_isRunning = false;
|
||||||
|
|
||||||
|
// some clients will use these menu features
|
||||||
_wantMenuItems = wantMenuItems;
|
_wantMenuItems = wantMenuItems;
|
||||||
if (scriptMenuName) {
|
if (scriptMenuName) {
|
||||||
_scriptMenuName = "Stop ";
|
_scriptMenuName = "Stop ";
|
||||||
|
@ -38,6 +42,7 @@ ScriptEngine::ScriptEngine(QString scriptContents, bool wantMenuItems,
|
||||||
_scriptMenuName.append(_scriptNumber);
|
_scriptMenuName.append(_scriptNumber);
|
||||||
}
|
}
|
||||||
_menu = menu;
|
_menu = menu;
|
||||||
|
_controllerScriptingInterface = controllerScriptingInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptEngine::~ScriptEngine() {
|
ScriptEngine::~ScriptEngine() {
|
||||||
|
@ -57,10 +62,16 @@ void ScriptEngine::cleanMenuItems() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::run() {
|
bool ScriptEngine::setScriptContents(const QString& scriptContents) {
|
||||||
|
if (_isRunning) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_scriptContents = scriptContents;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//setupMenuItems();
|
void ScriptEngine::run() {
|
||||||
|
_isRunning = true;
|
||||||
QScriptEngine engine;
|
QScriptEngine engine;
|
||||||
|
|
||||||
_voxelScriptingInterface.init();
|
_voxelScriptingInterface.init();
|
||||||
|
@ -78,6 +89,11 @@ void ScriptEngine::run() {
|
||||||
QScriptValue particleScripterValue = engine.newQObject(&_particleScriptingInterface);
|
QScriptValue particleScripterValue = engine.newQObject(&_particleScriptingInterface);
|
||||||
engine.globalObject().setProperty("Particles", particleScripterValue);
|
engine.globalObject().setProperty("Particles", particleScripterValue);
|
||||||
|
|
||||||
|
if (_controllerScriptingInterface) {
|
||||||
|
QScriptValue controllerScripterValue = engine.newQObject(_controllerScriptingInterface);
|
||||||
|
engine.globalObject().setProperty("Controller", controllerScripterValue);
|
||||||
|
}
|
||||||
|
|
||||||
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
|
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
|
||||||
engine.globalObject().setProperty("TREE_SCALE", treeScaleValue);
|
engine.globalObject().setProperty("TREE_SCALE", treeScaleValue);
|
||||||
|
|
||||||
|
@ -107,16 +123,14 @@ void ScriptEngine::run() {
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isFinished) {
|
if (_isFinished) {
|
||||||
//qDebug() << "line: " << __LINE__ << " _isFinished... breaking loop\n";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
if (_isFinished) {
|
if (_isFinished) {
|
||||||
//qDebug() << "line: " << __LINE__ << " _isFinished... breaking loop\n";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +143,9 @@ void ScriptEngine::run() {
|
||||||
_voxelScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages();
|
_voxelScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages();
|
||||||
|
|
||||||
// since we're in non-threaded mode, call process so that the packets are sent
|
// since we're in non-threaded mode, call process so that the packets are sent
|
||||||
//_voxelScriptingInterface.getVoxelPacketSender()->process();
|
if (!_voxelScriptingInterface.getVoxelPacketSender()->isThreaded()) {
|
||||||
|
_voxelScriptingInterface.getVoxelPacketSender()->process();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_particleScriptingInterface.getParticlePacketSender()->serversExist()) {
|
if (_particleScriptingInterface.getParticlePacketSender()->serversExist()) {
|
||||||
|
@ -140,14 +156,15 @@ void ScriptEngine::run() {
|
||||||
_particleScriptingInterface.getParticlePacketSender()->releaseQueuedMessages();
|
_particleScriptingInterface.getParticlePacketSender()->releaseQueuedMessages();
|
||||||
|
|
||||||
// since we're in non-threaded mode, call process so that the packets are sent
|
// since we're in non-threaded mode, call process so that the packets are sent
|
||||||
//_particleScriptingInterface.getParticlePacketSender()->process();
|
if (!_particleScriptingInterface.getParticlePacketSender()->isThreaded()) {
|
||||||
|
_particleScriptingInterface.getParticlePacketSender()->process();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (willSendVisualDataCallBack) {
|
if (willSendVisualDataCallBack) {
|
||||||
emit willSendVisualDataCallback();
|
emit willSendVisualDataCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (engine.hasUncaughtException()) {
|
if (engine.hasUncaughtException()) {
|
||||||
int line = engine.uncaughtExceptionLineNumber();
|
int line = engine.uncaughtExceptionLineNumber();
|
||||||
qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n";
|
qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n";
|
||||||
|
@ -161,9 +178,11 @@ void ScriptEngine::run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
emit finished();
|
emit finished();
|
||||||
|
_isRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::stop() {
|
void ScriptEngine::stop() {
|
||||||
_isFinished = true;
|
_isFinished = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,16 @@
|
||||||
#include <AbstractMenuInterface.h>
|
#include <AbstractMenuInterface.h>
|
||||||
#include <ParticleScriptingInterface.h>
|
#include <ParticleScriptingInterface.h>
|
||||||
#include <VoxelScriptingInterface.h>
|
#include <VoxelScriptingInterface.h>
|
||||||
|
#include "AbstractControllerScriptingInterface.h"
|
||||||
|
|
||||||
|
const QString NO_SCRIPT("");
|
||||||
|
|
||||||
class ScriptEngine : public QObject {
|
class ScriptEngine : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ScriptEngine(QString scriptContents, bool wantMenuItems = false,
|
ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false,
|
||||||
const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL);
|
const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL,
|
||||||
|
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
|
||||||
|
|
||||||
~ScriptEngine();
|
~ScriptEngine();
|
||||||
|
|
||||||
|
@ -33,6 +37,9 @@ public:
|
||||||
/// Access the ParticleScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
|
/// Access the ParticleScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
|
||||||
ParticleScriptingInterface* getParticleScriptingInterface() { return &_particleScriptingInterface; }
|
ParticleScriptingInterface* getParticleScriptingInterface() { return &_particleScriptingInterface; }
|
||||||
|
|
||||||
|
/// sets the script contents, will return false if failed, will fail if script is already running
|
||||||
|
bool setScriptContents(const QString& scriptContents);
|
||||||
|
|
||||||
void setupMenuItems();
|
void setupMenuItems();
|
||||||
void cleanMenuItems();
|
void cleanMenuItems();
|
||||||
|
|
||||||
|
@ -47,11 +54,13 @@ signals:
|
||||||
protected:
|
protected:
|
||||||
QString _scriptContents;
|
QString _scriptContents;
|
||||||
bool _isFinished;
|
bool _isFinished;
|
||||||
|
bool _isRunning;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VoxelScriptingInterface _voxelScriptingInterface;
|
VoxelScriptingInterface _voxelScriptingInterface;
|
||||||
ParticleScriptingInterface _particleScriptingInterface;
|
ParticleScriptingInterface _particleScriptingInterface;
|
||||||
|
AbstractControllerScriptingInterface* _controllerScriptingInterface;
|
||||||
bool _wantMenuItems;
|
bool _wantMenuItems;
|
||||||
QString _scriptMenuName;
|
QString _scriptMenuName;
|
||||||
AbstractMenuInterface* _menu;
|
AbstractMenuInterface* _menu;
|
|
@ -7,11 +7,12 @@ set(TARGET_NAME shared)
|
||||||
project(${TARGET_NAME})
|
project(${TARGET_NAME})
|
||||||
|
|
||||||
find_package(Qt5Network REQUIRED)
|
find_package(Qt5Network REQUIRED)
|
||||||
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
|
||||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||||
setup_hifi_library(${TARGET_NAME})
|
setup_hifi_library(${TARGET_NAME})
|
||||||
|
|
||||||
qt5_use_modules(${TARGET_NAME} Network)
|
qt5_use_modules(${TARGET_NAME} Network Widgets)
|
||||||
|
|
||||||
# include GLM
|
# include GLM
|
||||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||||
|
|
|
@ -10,9 +10,12 @@
|
||||||
#ifndef __hifi__AbstractMenuInterface__
|
#ifndef __hifi__AbstractMenuInterface__
|
||||||
#define __hifi__AbstractMenuInterface__
|
#define __hifi__AbstractMenuInterface__
|
||||||
|
|
||||||
#include <QMenuBar>
|
#include <QAction>
|
||||||
//#include <QHash>
|
|
||||||
//#include <QKeySequence>
|
class QMenu;
|
||||||
|
class QString;
|
||||||
|
class QObject;
|
||||||
|
class QKeySequence;
|
||||||
|
|
||||||
class AbstractMenuInterface {
|
class AbstractMenuInterface {
|
||||||
public:
|
public:
|
||||||
|
@ -26,4 +29,4 @@ public:
|
||||||
virtual void removeAction(QMenu* menu, const QString& actionName) = 0;
|
virtual void removeAction(QMenu* menu, const QString& actionName) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__AbstractMenuInterface__) */
|
#endif /* defined(__hifi__AbstractMenuInterface__) */
|
||||||
|
|
|
@ -33,6 +33,8 @@ public:
|
||||||
/// Override this function to do whatever your class actually does, return false to exit thread early.
|
/// Override this function to do whatever your class actually does, return false to exit thread early.
|
||||||
virtual bool process() = 0;
|
virtual bool process() = 0;
|
||||||
|
|
||||||
|
bool isThreaded() const { return _isThreaded; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/// Locks all the resources of the thread.
|
/// Locks all the resources of the thread.
|
||||||
|
@ -43,8 +45,6 @@ protected:
|
||||||
|
|
||||||
bool isStillRunning() const { return !_stopThread; }
|
bool isStillRunning() const { return !_stopThread; }
|
||||||
|
|
||||||
bool isThreaded() const { return _isThreaded; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pthread_mutex_t _mutex;
|
pthread_mutex_t _mutex;
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
case PACKET_TYPE_PARTICLE_DATA:
|
case PACKET_TYPE_PARTICLE_DATA:
|
||||||
return 3;
|
return 4;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
void registerMetaTypes(QScriptEngine* engine) {
|
void registerMetaTypes(QScriptEngine* engine) {
|
||||||
qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
|
qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
|
||||||
|
qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue);
|
||||||
qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue);
|
qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +30,19 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) {
|
||||||
vec3.z = object.property("z").toVariant().toFloat();
|
vec3.z = object.property("z").toVariant().toFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) {
|
||||||
|
QScriptValue obj = engine->newObject();
|
||||||
|
obj.setProperty("x", vec2.x);
|
||||||
|
obj.setProperty("y", vec2.y);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2) {
|
||||||
|
vec2.x = object.property("x").toVariant().toFloat();
|
||||||
|
vec2.y = object.property("y").toVariant().toFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color) {
|
QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color) {
|
||||||
QScriptValue obj = engine->newObject();
|
QScriptValue obj = engine->newObject();
|
||||||
obj.setProperty("red", color.red);
|
obj.setProperty("red", color.red);
|
||||||
|
|
|
@ -17,11 +17,17 @@
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(glm::vec3)
|
Q_DECLARE_METATYPE(glm::vec3)
|
||||||
|
Q_DECLARE_METATYPE(glm::vec2)
|
||||||
Q_DECLARE_METATYPE(xColor)
|
Q_DECLARE_METATYPE(xColor)
|
||||||
|
|
||||||
void registerMetaTypes(QScriptEngine* engine);
|
void registerMetaTypes(QScriptEngine* engine);
|
||||||
|
|
||||||
QScriptValue vec3toScriptValue(QScriptEngine* engine, const glm::vec3 &vec3);
|
QScriptValue vec3toScriptValue(QScriptEngine* engine, const glm::vec3 &vec3);
|
||||||
void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3);
|
void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3);
|
||||||
|
|
||||||
|
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2);
|
||||||
|
void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2);
|
||||||
|
|
||||||
QScriptValue xColorToScriptValue(QScriptEngine* engine, const xColor& color);
|
QScriptValue xColorToScriptValue(QScriptEngine* engine, const xColor& color);
|
||||||
void xColorFromScriptValue(const QScriptValue &object, xColor& color);
|
void xColorFromScriptValue(const QScriptValue &object, xColor& color);
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,15 @@ uint64_t usecTimestamp(const timeval *time) {
|
||||||
return (time->tv_sec * 1000000 + time->tv_usec);
|
return (time->tv_sec * 1000000 + time->tv_usec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int usecTimestampNowAdjust = 0;
|
||||||
|
void usecTimestampNowForceClockSkew(int clockSkew) {
|
||||||
|
::usecTimestampNowAdjust = clockSkew;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t usecTimestampNow() {
|
uint64_t usecTimestampNow() {
|
||||||
timeval now;
|
timeval now;
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
return (now.tv_sec * 1000000 + now.tv_usec);
|
return (now.tv_sec * 1000000 + now.tv_usec) + ::usecTimestampNowAdjust;
|
||||||
}
|
}
|
||||||
|
|
||||||
float randFloat () {
|
float randFloat () {
|
||||||
|
|
|
@ -56,6 +56,7 @@ static const uint64_t USECS_PER_SECOND = 1000 * 1000;
|
||||||
|
|
||||||
uint64_t usecTimestamp(const timeval *time);
|
uint64_t usecTimestamp(const timeval *time);
|
||||||
uint64_t usecTimestampNow();
|
uint64_t usecTimestampNow();
|
||||||
|
void usecTimestampNowForceClockSkew(int clockSkew);
|
||||||
|
|
||||||
float randFloat();
|
float randFloat();
|
||||||
int randIntInRange (int min, int max);
|
int randIntInRange (int min, int max);
|
||||||
|
|
Loading…
Reference in a new issue