This commit is contained in:
Stephen Birarda 2014-01-02 09:00:14 -08:00
commit a0cf2c8fb1
24 changed files with 606 additions and 350 deletions

View file

@ -32,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:
_scriptEngine.getVoxelScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr, _scriptEngine.getVoxelsScriptingInterface()->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:
_scriptEngine.getParticleScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr, _scriptEngine.getParticlesScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr,
(unsigned char*) dataByteArray.data(), (unsigned char*) dataByteArray.data(),
dataByteArray.size()); dataByteArray.size());
break; break;

View file

@ -18,9 +18,6 @@
#include <ScriptEngine.h> #include <ScriptEngine.h>
#include <ThreadedAssignment.h> #include <ThreadedAssignment.h>
#include <VoxelScriptingInterface.h>
#include <ParticleScriptingInterface.h>
class Agent : public ThreadedAssignment { class Agent : public ThreadedAssignment {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -0,0 +1,149 @@
var currentIteration = 0;
var NUM_ITERATIONS_BEFORE_SEND = 15; // every 1/4th seconds send another
var numberParticlesAdded = 0;
var MAX_PARTICLES = 1;
var velocity = {
x: 1/TREE_SCALE,
y: 0/TREE_SCALE,
z: 1/TREE_SCALE };
var gravity = {
x: 0/TREE_SCALE,
y: 0/TREE_SCALE,
z: 0/TREE_SCALE };
var damping = 0.1;
var scriptA = " " +
//" function update() { " +
//" print('update()\\n'); " +
//" var color = { red: 255, green: 127 + (Math.random() * 128), blue: 0 };" +
//" Particle.setColor(color); " +
//" } " +
" function collisionWithParticle(other) { " +
" print('collisionWithParticle(other.getID()=' + other.getID() + ')...'); " +
" print('myID=' + Particle.getID() + '\\n'); " +
" var colorBlack = { red: 0, green: 0, blue: 0 };" +
" var otherColor = other.getColor();" +
" print('otherColor=' + otherColor.red + ', ' + otherColor.green + ', ' + otherColor.blue + '\\n'); " +
" var myColor = Particle.getColor();" +
" print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " +
" Particle.setColor(otherColor); " +
" other.setColor(myColor); " +
" } " +
" function collisionWithVoxel(voxel) { " +
" print('collisionWithVoxel(voxel)... '); " +
" print('myID=' + Particle.getID() + '\\n'); " +
" var voxelColor = voxel.getColor();" +
" print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " +
" var myColor = Particle.getColor();" +
" print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " +
" Particle.setColor(voxelColor); " +
" } " +
" Particle.collisionWithParticle.connect(collisionWithParticle); " +
" Particle.collisionWithVoxel.connect(collisionWithVoxel); " +
" ";
var scriptB = " " +
" function collisionWithParticle(other) { " +
" print('collisionWithParticle(other.getID()=' + other.getID() + ')...'); " +
" print('myID=' + Particle.getID() + '\\n'); " +
" var myPosition = Particle.getPosition();" +
" var myRadius = Particle.getRadius();" +
" var myColor = Particle.getColor();" +
" Voxels.queueDestructiveVoxelAdd(myPosition.x, myPosition.y, myPosition.z, myRadius, myColor.red, myColor.green, myColor.blue); " +
" Particle.setScript('Particle.setShouldDie(true);'); " +
" } " +
" function collisionWithVoxel(voxel) { " +
" print('collisionWithVoxel(voxel)... '); " +
" print('myID=' + Particle.getID() + '\\n'); " +
" var voxelColor = voxel.getColor();" +
" print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " +
" var myColor = Particle.getColor();" +
" print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " +
" Particle.setColor(voxelColor); " +
" } " +
" Particle.collisionWithParticle.connect(collisionWithParticle); " +
" Particle.collisionWithVoxel.connect(collisionWithVoxel); " +
" ";
var color = {
red: 255,
green: 255,
blue: 0 };
function draw() {
print("hello... draw()... currentIteration=" + currentIteration + "\n");
// on the first iteration, setup a single particle that's slowly moving
if (currentIteration == 0) {
var colorGreen = { red: 0, green: 255, blue: 0 };
var startPosition = {
x: 2/TREE_SCALE,
y: 0/TREE_SCALE,
z: 2/TREE_SCALE };
var largeRadius = 0.5/TREE_SCALE;
var verySlow = {
x: 0.01/TREE_SCALE,
y: 0/TREE_SCALE,
z: 0.01/TREE_SCALE };
Particles.queueParticleAdd(startPosition, largeRadius, colorGreen, verySlow, gravity, damping, false, scriptA);
print("hello... added particle... script=\n");
print(scriptA);
numberParticlesAdded++;
}
if (currentIteration++ % NUM_ITERATIONS_BEFORE_SEND === 0) {
print("draw()... sending another... currentIteration=" +currentIteration + "\n");
var center = {
x: 0/TREE_SCALE,
y: 0/TREE_SCALE,
z: 0/TREE_SCALE };
var particleSize = 0.1 / TREE_SCALE;
print("number of particles=" + numberParticlesAdded +"\n");
var velocityStep = 0.1/TREE_SCALE;
if (velocity.x > 0) {
velocity.x -= velocityStep;
velocity.z += velocityStep;
color.blue = 0;
color.green = 255;
} else {
velocity.x += velocityStep;
velocity.z -= velocityStep;
color.blue = 255;
color.green = 0;
}
if (numberParticlesAdded <= MAX_PARTICLES) {
Particles.queueParticleAdd(center, particleSize, color, velocity, gravity, damping, false, scriptB);
print("hello... added particle... script=\n");
print(scriptB);
numberParticlesAdded++;
} else {
Agent.stop();
}
print("Particles Stats: " + Particles.getLifetimeInSeconds() + " seconds," +
" Queued packets:" + Particles.getLifetimePacketsQueued() + "," +
" PPS:" + Particles.getLifetimePPSQueued() + "," +
" BPS:" + Particles.getLifetimeBPSQueued() + "," +
" Sent packets:" + Particles.getLifetimePacketsSent() + "," +
" PPS:" + Particles.getLifetimePPS() + "," +
" BPS:" + Particles.getLifetimeBPS() +
"\n");
}
}
// register the call back so it fires before each data send
print("here...\n");
Particles.setPacketsPerSecond(40000);
Agent.willSendVisualDataCallback.connect(draw);
print("and here...\n");

98
examples/gun.js Normal file
View file

@ -0,0 +1,98 @@
// initialize our triggers
var triggerPulled = new Array();
var numberOfTriggers = Controller.getNumberOfTriggers();
for (t = 0; t < numberOfTriggers; t++) {
triggerPulled[t] = false;
}
function checkController() {
var numberOfTriggers = Controller.getNumberOfTriggers();
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
//print("numberOfTriggers:" + numberOfTriggers + "\n");
//print("numberOfSpatialControls:" + numberOfSpatialControls + "\n");
//print("controllersPerTrigger:" + controllersPerTrigger + "\n");
// this is expected for hydras
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
for (var t = 0; t < numberOfTriggers; t++) {
var shootABullet = false;
var triggerValue = Controller.getTriggerValue(t);
if (triggerPulled[t]) {
// must release to at least 0.1
if (triggerValue < 0.1) {
triggerPulled[t] = false; // unpulled
}
} else {
// must pull to at least 0.9
if (triggerValue > 0.9) {
triggerPulled[t] = true; // pulled
shootABullet = true;
}
}
if (shootABullet) {
var palmController = t * controllersPerTrigger;
var palmPosition = Controller.getSpatialControlPosition(palmController);
var fingerTipController = palmController + 1;
var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
var bulletSize = 0.25/TREE_SCALE;
var palmInParticleSpace =
{ x: palmPosition.x/TREE_SCALE,
y: palmPosition.y/TREE_SCALE,
z: palmPosition.z/TREE_SCALE };
var tipInParticleSpace =
{ x: fingerTipPosition.x/TREE_SCALE,
y: fingerTipPosition.y/TREE_SCALE,
z: fingerTipPosition.z/TREE_SCALE };
var palmToFingerTipVector =
{ x: (tipInParticleSpace.x - palmInParticleSpace.x),
y: (tipInParticleSpace.y - palmInParticleSpace.y),
z: (tipInParticleSpace.z - palmInParticleSpace.z) };
// just off the front of the finger tip
var position = { x: tipInParticleSpace.x + palmToFingerTipVector.x/2,
y: tipInParticleSpace.y + palmToFingerTipVector.y/2,
z: tipInParticleSpace.z + palmToFingerTipVector.z/2};
var linearVelocity = 50; // 50 meters per second
var velocity = { x: palmToFingerTipVector.x * linearVelocity,
y: palmToFingerTipVector.y * linearVelocity,
z: palmToFingerTipVector.z * linearVelocity };
var gravity = { x: 0, y: -0.1/TREE_SCALE, z: 0 }; // gravity has no effect on these bullets
var color = { red: 128, green: 128, blue: 128 };
var damping = 0; // no damping
var inHand = false;
var script =
" function collisionWithVoxel(voxel) { " +
" print('collisionWithVoxel(voxel)... '); " +
" print('myID=' + Particle.getID() + '\\n'); " +
" var voxelColor = voxel.getColor();" +
" print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " +
" var myColor = Particle.getColor();" +
" print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " +
" Particle.setColor(voxelColor); " +
" var voxelAt = voxel.getPosition();" +
" var voxelScale = voxel.getScale();" +
" Voxels.queueVoxelDelete(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " +
" print('Voxels.queueVoxelDelete(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " +
" } " +
" Particle.collisionWithVoxel.connect(collisionWithVoxel); ";
Particles.queueParticleAdd(position, bulletSize, color, velocity, gravity, damping, inHand, script);
}
}
}
}
// register the call back so it fires before each data send
Agent.willSendVisualDataCallback.connect(checkController);

View file

@ -1518,10 +1518,21 @@ void Application::shootParticle() {
glm::vec3 velocity = lookingAt - position; glm::vec3 velocity = lookingAt - position;
glm::vec3 gravity = DEFAULT_GRAVITY * 0.f; glm::vec3 gravity = DEFAULT_GRAVITY * 0.f;
float damping = DEFAULT_DAMPING * 0.01f; float damping = DEFAULT_DAMPING * 0.01f;
QString updateScript(""); QString script(
" function collisionWithVoxel(voxel) { "
" print('collisionWithVoxel(voxel)... '); "
" print('myID=' + Particle.getID() + '\\n'); "
" var voxelColor = voxel.getColor();"
" print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); "
" var myColor = Particle.getColor();"
" print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); "
" Particle.setColor(voxelColor); "
" } "
" Particle.collisionWithVoxel.connect(collisionWithVoxel); " );
ParticleEditHandle* particleEditHandle = makeParticle(position / (float)TREE_SCALE, radius, color, ParticleEditHandle* particleEditHandle = makeParticle(position / (float)TREE_SCALE, radius, color,
velocity / (float)TREE_SCALE, gravity, damping, NOT_IN_HAND, updateScript); velocity / (float)TREE_SCALE, gravity, damping, NOT_IN_HAND, script);
// If we wanted to be able to edit this particle after shooting, then we could store this value // If we wanted to be able to edit this particle after shooting, then we could store this value
// and use it for editing later. But we don't care about that for "shooting" and therefore we just // and use it for editing later. But we don't care about that for "shooting" and therefore we just
@ -4455,8 +4466,8 @@ void Application::loadScript() {
// 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
// we can use the same ones from the application. // we can use the same ones from the application.
scriptEngine->getVoxelScriptingInterface()->setPacketSender(&_voxelEditSender); scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender);
scriptEngine->getParticleScriptingInterface()->setPacketSender(&_particleEditSender); scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
QThread* workerThread = new QThread(this); QThread* workerThread = new QThread(this);

View file

@ -1,147 +0,0 @@
//
// Balls.cpp
// hifi
//
// Created by Philip on 4/25/13.
//
// A cloud of spring-mass spheres to simulate the avatar body/skin. Each ball
// connects to as many as 4 neighbors, and executes motion according to a damped
// spring, while responding physically to other avatars.
//
#include <glm/glm.hpp>
#include <SharedUtil.h>
#include "Balls.h"
#include "InterfaceConfig.h"
#include "Util.h"
#include "world.h"
const float INITIAL_AREA = 0.2f;
const float BALL_RADIUS = 0.016f;
const glm::vec3 INITIAL_COLOR(0.62f, 0.74f, 0.91f);
Balls::Balls(int numberOfBalls) {
_numberOfBalls = numberOfBalls;
_balls = new Ball[_numberOfBalls];
for (unsigned int i = 0; i < _numberOfBalls; ++i) {
_balls[i].position = randVector() * INITIAL_AREA;
_balls[i].targetPosition = _balls[i].position;
_balls[i].velocity = glm::vec3(0, 0, 0);
_balls[i].radius = BALL_RADIUS;
for (unsigned int j = 0; j < NUMBER_SPRINGS; ++j) {
_balls[i].links[j] = 0;
}
}
_color = INITIAL_COLOR;
_origin = glm::vec3(0, 0, 0);
}
Balls::~Balls() {
delete[] _balls;
}
void Balls::moveOrigin(const glm::vec3& newOrigin) {
glm::vec3 delta = newOrigin - _origin;
if (glm::length(delta) > EPSILON) {
_origin = newOrigin;
for (unsigned int i = 0; i < _numberOfBalls; ++i) {
_balls[i].targetPosition += delta;
}
}
}
const bool RENDER_SPRINGS = false;
void Balls::render() {
// Render Balls NOTE: This needs to become something other that GlutSpheres!
glColor3fv(&_color.x);
for (unsigned int i = 0; i < _numberOfBalls; ++i) {
glPushMatrix();
glTranslatef(_balls[i].position.x, _balls[i].position.y, _balls[i].position.z);
glutSolidSphere(_balls[i].radius, 8, 8);
glPopMatrix();
}
// Render springs
if (RENDER_SPRINGS) {
glColor3f(0.74, 0.91, 0.62);
for (unsigned int i = 0; i < _numberOfBalls; ++i) {
glBegin(GL_LINES);
for (unsigned int j = 0; j < NUMBER_SPRINGS; ++j) {
if(_balls[i].links[j] > 0) {
glVertex3f(_balls[i].position.x,
_balls[i].position.y,
_balls[i].position.z);
glVertex3f(_balls[_balls[i].links[j]-1].position.x,
_balls[_balls[i].links[j]-1].position.y,
_balls[_balls[i].links[j]-1].position.z);
}
}
glEnd();
}
}
}
const float CONSTANT_VELOCITY_DAMPING = 1.0f;
const float NOISE_SCALE = 0.06;
const float SPRING_FORCE = 30.0;
const float ORIGIN_DISTANCE = 0.1;
const float SPRING_DAMPING = 1.0;
void Balls::simulate(float deltaTime) {
for (unsigned int i = 0; i < _numberOfBalls; ++i) {
// Move particles
_balls[i].position += _balls[i].velocity * deltaTime;
_balls[i].targetPosition += _balls[i].velocity * deltaTime;
// Drag: decay velocity
_balls[i].velocity *= (1.f - CONSTANT_VELOCITY_DAMPING * deltaTime);
// Add noise
_balls[i].velocity += randVector() * NOISE_SCALE;
// spring force to origin
float separation = glm::distance(_balls[i].position,
_origin);
_balls[i].velocity +=
glm::normalize(_balls[i].position - _origin)
* deltaTime
*
SPRING_FORCE *
(ORIGIN_DISTANCE - separation);
// Approach target position
// for (unsigned int i = 0; i < _numberOfBalls; ++i) {
// _balls[i].position += randFloat() * deltaTime * (_balls[i].targetPosition - _balls[i].position);
// }
// Spring Force
/*
for (unsigned int j = 0; j < NUMBER_SPRINGS; ++j) {
if(_balls[i].links[j] > 0) {
float separation = glm::distance(_balls[i].position,
_balls[_balls[i].links[j]-1].position);
_balls[i].velocity += glm::normalize(_balls[i].position -
_balls[_balls[i].links[j]-1].position) *
deltaTime *
SPRING_FORCE *
(_balls[i].springLength[j] - separation);
//_balls[i].velocity *= (1.f - SPRING_DAMPING*deltaTime);
}
} */
}
}

View file

@ -1,37 +0,0 @@
//
// Balls.h
// hifi
//
// Created by Philip on 4/25/13.
//
//
#ifndef hifi_Balls_h
#define hifi_Balls_h
const int NUMBER_SPRINGS = 4;
class Balls {
public:
Balls(int numberOfBalls);
~Balls();
void simulate(float deltaTime);
void render();
void setColor(const glm::vec3& c) { _color = c; };
void moveOrigin(const glm::vec3& newOrigin);
private:
struct Ball {
glm::vec3 position, targetPosition, velocity;
int links[NUMBER_SPRINGS];
float springLength[NUMBER_SPRINGS];
float radius;
} *_balls;
int _numberOfBalls;
glm::vec3 _origin;
glm::vec3 _color;
};
#endif

View file

@ -59,8 +59,8 @@ const float HEAD_RATE_MAX = 50.f;
const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; const float SKIN_COLOR[] = {1.0, 0.84, 0.66};
const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63};
const int NUM_BODY_CONE_SIDES = 9; const int NUM_BODY_CONE_SIDES = 9;
const float chatMessageScale = 0.0015; const float CHAT_MESSAGE_SCALE = 0.0015;
const float chatMessageHeight = 0.4f; const float CHAT_MESSAGE_HEIGHT = 0.1f;
void Avatar::sendAvatarURLsMessage(const QUrl& voxelURL) { void Avatar::sendAvatarURLsMessage(const QUrl& voxelURL) {
QByteArray message; QByteArray message;
@ -118,18 +118,12 @@ Avatar::Avatar(Node* owningNode) :
_pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight(); _pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight();
_pelvisToHeadLength = _skeleton.getPelvisToHeadLength(); _pelvisToHeadLength = _skeleton.getPelvisToHeadLength();
if (BALLS_ON) {
_balls = new Balls(100);
} else {
_balls = NULL;
}
} }
Avatar::~Avatar() { Avatar::~Avatar() {
_headData = NULL; _headData = NULL;
_handData = NULL; _handData = NULL;
delete _balls;
} }
void Avatar::deleteOrDeleteLater() { void Avatar::deleteOrDeleteLater() {
@ -180,18 +174,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
// copy velocity so we can use it later for acceleration // copy velocity so we can use it later for acceleration
glm::vec3 oldVelocity = getVelocity(); glm::vec3 oldVelocity = getVelocity();
// update balls
if (_balls) {
_balls->moveOrigin(_position);
glm::vec3 lookAt = _head.getLookAtPosition();
if (glm::length(lookAt) > EPSILON) {
_balls->moveOrigin(lookAt);
} else {
_balls->moveOrigin(_position);
}
_balls->simulate(deltaTime);
}
// update torso rotation based on head lean // update torso rotation based on head lean
_skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::radians(glm::vec3( _skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::radians(glm::vec3(
_head.getLeanForward(), 0.0f, _head.getLeanSideways()))); _head.getLeanForward(), 0.0f, _head.getLeanSideways())));
@ -288,13 +270,7 @@ void Avatar::render(bool forceRenderHead) {
} }
} }
// Render the balls
if (_balls) {
glPushMatrix();
_balls->render();
glPopMatrix();
}
if (!_chatMessage.empty()) { if (!_chatMessage.empty()) {
int width = 0; int width = 0;
int lastWidth = 0; int lastWidth = 0;
@ -303,7 +279,7 @@ void Avatar::render(bool forceRenderHead) {
} }
glPushMatrix(); glPushMatrix();
glm::vec3 chatPosition = getPosition() + getBodyUpDirection() * chatMessageHeight * _scale; glm::vec3 chatPosition = getHead().getEyePosition() + getBodyUpDirection() * CHAT_MESSAGE_HEIGHT * _scale;
glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z); glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z);
glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation(); glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation();
glm::vec3 chatAxis = glm::axis(chatRotation); glm::vec3 chatAxis = glm::axis(chatRotation);
@ -313,7 +289,7 @@ void Avatar::render(bool forceRenderHead) {
glColor3f(0, 0.8, 0); glColor3f(0, 0.8, 0);
glRotatef(180, 0, 1, 0); glRotatef(180, 0, 1, 0);
glRotatef(180, 0, 0, 1); glRotatef(180, 0, 0, 1);
glScalef(_scale * chatMessageScale, _scale * chatMessageScale, 1.0f); glScalef(_scale * CHAT_MESSAGE_SCALE, _scale * CHAT_MESSAGE_SCALE, 1.0f);
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
glDepthMask(false); glDepthMask(false);

View file

@ -15,7 +15,6 @@
#include <AvatarData.h> #include <AvatarData.h>
#include "Balls.h"
#include "Hand.h" #include "Hand.h"
#include "Head.h" #include "Head.h"
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
@ -58,8 +57,8 @@ const float BODY_BALL_RADIUS_RIGHT_TOES = 0.025;
extern const bool usingBigSphereCollisionTest; extern const bool usingBigSphereCollisionTest;
extern const float chatMessageScale; extern const float CHAT_MESSAGE_SCALE;
extern const float chatMessageHeight; extern const float CHAT_MESSAGE_HEIGHT;
enum AvatarBodyBallID { enum AvatarBodyBallID {
BODY_BALL_NULL = -1, BODY_BALL_NULL = -1,
@ -214,7 +213,6 @@ protected:
float _pelvisToHeadLength; float _pelvisToHeadLength;
float _scale; float _scale;
float _height; float _height;
Balls* _balls;
glm::vec3 _worldUpDirection; glm::vec3 _worldUpDirection;
glm::vec3 _mouseRayOrigin; glm::vec3 _mouseRayOrigin;
glm::vec3 _mouseRayDirection; glm::vec3 _mouseRayDirection;

View file

@ -52,6 +52,8 @@ Hand::Hand(Avatar* owningAvatar) :
_pitchUpdate(0), _pitchUpdate(0),
_grabDelta(0, 0, 0), _grabDelta(0, 0, 0),
_grabDeltaVelocity(0, 0, 0), _grabDeltaVelocity(0, 0, 0),
_grabStartRotation(0, 0, 0, 1),
_grabCurrentRotation(0, 0, 0, 1),
_throwInjector(QUrl("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw")), _throwInjector(QUrl("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw")),
_catchInjector(QUrl("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw")) _catchInjector(QUrl("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"))
{ {
@ -116,7 +118,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
NO_GRAVITY, NO_GRAVITY,
NO_DAMPING, NO_DAMPING,
IN_HAND, // we just grabbed it! IN_HAND, // we just grabbed it!
closestParticle->getUpdateScript()); closestParticle->getScript());
// now tell our hand about us having caught it... // now tell our hand about us having caught it...
@ -227,7 +229,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
} }
glm::vec3 Hand::getAndResetGrabDelta() { glm::vec3 Hand::getAndResetGrabDelta() {
const float HAND_GRAB_SCALE_DISTANCE = 5.f; const float HAND_GRAB_SCALE_DISTANCE = 2.f;
glm::vec3 delta = _grabDelta * _owningAvatar->getScale() * HAND_GRAB_SCALE_DISTANCE; glm::vec3 delta = _grabDelta * _owningAvatar->getScale() * HAND_GRAB_SCALE_DISTANCE;
_grabDelta = glm::vec3(0,0,0); _grabDelta = glm::vec3(0,0,0);
glm::quat avatarRotation = _owningAvatar->getOrientation(); glm::quat avatarRotation = _owningAvatar->getOrientation();
@ -242,6 +244,11 @@ glm::vec3 Hand::getAndResetGrabDeltaVelocity() {
return avatarRotation * -delta; return avatarRotation * -delta;
} }
glm::quat Hand::getAndResetGrabRotation() {
glm::quat diff = _grabCurrentRotation * glm::inverse(_grabStartRotation);
_grabStartRotation = _grabCurrentRotation;
return diff;
}
void Hand::simulate(float deltaTime, bool isMine) { void Hand::simulate(float deltaTime, bool isMine) {
@ -275,10 +282,16 @@ void Hand::simulate(float deltaTime, bool isMine) {
if (palm.getControllerButtons() & BUTTON_4) { if (palm.getControllerButtons() & BUTTON_4) {
_grabDelta += palm.getRawVelocity() * deltaTime; _grabDelta += palm.getRawVelocity() * deltaTime;
_grabCurrentRotation = palm.getRawRotation();
} }
if ((palm.getLastControllerButtons() & BUTTON_4) && !(palm.getControllerButtons() & BUTTON_4)) { if ((palm.getLastControllerButtons() & BUTTON_4) && !(palm.getControllerButtons() & BUTTON_4)) {
// Just ending grab, capture velocity
_grabDeltaVelocity = palm.getRawVelocity(); _grabDeltaVelocity = palm.getRawVelocity();
} }
if (!(palm.getLastControllerButtons() & BUTTON_4) && (palm.getControllerButtons() & BUTTON_4)) {
// Just starting grab, capture starting rotation
_grabStartRotation = palm.getRawRotation();
}
if (palm.getControllerButtons() & BUTTON_1) { if (palm.getControllerButtons() & BUTTON_1) {
if (glm::length(fingerTipPosition - _lastFingerAddVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) { if (glm::length(fingerTipPosition - _lastFingerAddVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) {

View file

@ -21,7 +21,6 @@
#include <HandData.h> #include <HandData.h>
#include <ParticleEditHandle.h> #include <ParticleEditHandle.h>
#include "Balls.h"
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
#include "ParticleSystem.h" #include "ParticleSystem.h"
#include "world.h" #include "world.h"
@ -65,6 +64,7 @@ public:
// Get the drag distance to move // Get the drag distance to move
glm::vec3 getAndResetGrabDelta(); glm::vec3 getAndResetGrabDelta();
glm::vec3 getAndResetGrabDeltaVelocity(); glm::vec3 getAndResetGrabDeltaVelocity();
glm::quat getAndResetGrabRotation();
private: private:
// disallow copies of the Hand, copy of owning Avatar is disallowed too // disallow copies of the Hand, copy of owning Avatar is disallowed too
@ -111,6 +111,8 @@ private:
glm::vec3 _grabDelta; glm::vec3 _grabDelta;
glm::vec3 _grabDeltaVelocity; glm::vec3 _grabDeltaVelocity;
glm::quat _grabStartRotation;
glm::quat _grabCurrentRotation;
AudioInjector _throwInjector; AudioInjector _throwInjector;
AudioInjector _catchInjector; AudioInjector _catchInjector;

View file

@ -111,18 +111,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
// calculate speed // calculate speed
_speed = glm::length(_velocity); _speed = glm::length(_velocity);
// update balls
if (_balls) {
_balls->moveOrigin(_position);
glm::vec3 lookAt = _head.getLookAtPosition();
if (glm::length(lookAt) > EPSILON) {
_balls->moveOrigin(lookAt);
} else {
_balls->moveOrigin(_position);
}
_balls->simulate(deltaTime);
}
// update torso rotation based on head lean // update torso rotation based on head lean
_skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::radians(glm::vec3( _skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::radians(glm::vec3(
_head.getLeanForward(), 0.0f, _head.getLeanSideways()))); _head.getLeanForward(), 0.0f, _head.getLeanSideways())));
@ -270,14 +258,21 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
} }
updateChatCircle(deltaTime); updateChatCircle(deltaTime);
// Get any position or velocity update from Grab controller // Get any position, velocity, or rotation update from Grab Drag controller
glm::vec3 moveFromGrab = _hand.getAndResetGrabDelta(); glm::vec3 moveFromGrab = _hand.getAndResetGrabDelta();
if (glm::length(moveFromGrab) > EPSILON) { if (glm::length(moveFromGrab) > EPSILON) {
_position += moveFromGrab; _position += moveFromGrab;
_velocity = glm::vec3(0, 0, 0); _velocity = glm::vec3(0, 0, 0);
} }
_velocity += _hand.getAndResetGrabDeltaVelocity(); _velocity += _hand.getAndResetGrabDeltaVelocity();
glm::quat deltaRotation = _hand.getAndResetGrabRotation();
const float GRAB_CONTROLLER_TURN_SCALING = 0.5f;
glm::vec3 euler = safeEulerAngles(deltaRotation) * GRAB_CONTROLLER_TURN_SCALING;
// Adjust body yaw by yaw from controller
setOrientation(glm::angleAxis(-euler.y, glm::vec3(0, 1, 0)) * getOrientation());
// Adjust head pitch from controller
getHead().setMousePitch(getHead().getMousePitch() - euler.x);
_position += _velocity * deltaTime; _position += _velocity * deltaTime;
@ -455,17 +450,9 @@ void MyAvatar::render(bool forceRenderHead) {
// render body // render body
renderBody(forceRenderHead); renderBody(forceRenderHead);
// Render the balls
if (_balls) {
glPushMatrix();
_balls->render();
glPopMatrix();
}
//renderDebugBodyPoints(); //renderDebugBodyPoints();
if (!_chatMessage.empty()) { if (!_chatMessage.empty()) {
int width = 0; int width = 0;
int lastWidth = 0; int lastWidth = 0;
@ -474,7 +461,7 @@ void MyAvatar::render(bool forceRenderHead) {
} }
glPushMatrix(); glPushMatrix();
glm::vec3 chatPosition = getPosition() + getBodyUpDirection() * chatMessageHeight * _scale; glm::vec3 chatPosition = getHead().getEyePosition() + getBodyUpDirection() * CHAT_MESSAGE_HEIGHT * _scale;
glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z); glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z);
glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation(); glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation();
glm::vec3 chatAxis = glm::axis(chatRotation); glm::vec3 chatAxis = glm::axis(chatRotation);
@ -484,7 +471,7 @@ void MyAvatar::render(bool forceRenderHead) {
glColor3f(0, 0.8, 0); glColor3f(0, 0.8, 0);
glRotatef(180, 0, 1, 0); glRotatef(180, 0, 1, 0);
glRotatef(180, 0, 0, 1); glRotatef(180, 0, 0, 1);
glScalef(_scale * chatMessageScale, _scale * chatMessageScale, 1.0f); glScalef(_scale * CHAT_MESSAGE_SCALE, _scale * CHAT_MESSAGE_SCALE, 1.0f);
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
glDepthMask(false); glDepthMask(false);

View file

@ -14,9 +14,14 @@
#include <SharedUtil.h> // usecTimestampNow() #include <SharedUtil.h> // usecTimestampNow()
#include <Octree.h> #include <Octree.h>
#include <VoxelsScriptingInterface.h>
#include "ParticlesScriptingInterface.h"
#include "Particle.h" #include "Particle.h"
uint32_t Particle::_nextID = 0; uint32_t Particle::_nextID = 0;
VoxelsScriptingInterface* Particle::_voxelsScriptingInterface = NULL;
ParticlesScriptingInterface* Particle::_particlesScriptingInterface = NULL;
Particle::Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity, Particle::Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity,
@ -53,8 +58,9 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3
_velocity = velocity; _velocity = velocity;
_damping = damping; _damping = damping;
_gravity = gravity; _gravity = gravity;
_updateScript = updateScript; _script = updateScript;
_inHand = inHand; _inHand = inHand;
_shouldDie = false;
} }
@ -95,10 +101,10 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
success = packetData->appendValue(getInHand()); success = packetData->appendValue(getInHand());
} }
if (success) { if (success) {
uint16_t scriptLength = _updateScript.size() + 1; // include NULL uint16_t scriptLength = _script.size() + 1; // include NULL
success = packetData->appendValue(scriptLength); success = packetData->appendValue(scriptLength);
if (success) { if (success) {
success = packetData->appendRawData((const unsigned char*)qPrintable(_updateScript), scriptLength); success = packetData->appendRawData((const unsigned char*)qPrintable(_script), scriptLength);
} }
} }
return success; return success;
@ -206,7 +212,7 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += sizeof(scriptLength); dataAt += sizeof(scriptLength);
bytesRead += sizeof(scriptLength); bytesRead += sizeof(scriptLength);
QString tempString((const char*)dataAt); QString tempString((const char*)dataAt);
_updateScript = tempString; _script = tempString;
dataAt += scriptLength; dataAt += scriptLength;
bytesRead += scriptLength; bytesRead += scriptLength;
@ -299,7 +305,7 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
dataAt += sizeof(scriptLength); dataAt += sizeof(scriptLength);
processedBytes += sizeof(scriptLength); processedBytes += sizeof(scriptLength);
QString tempString((const char*)dataAt); QString tempString((const char*)dataAt);
newParticle._updateScript = tempString; newParticle._script = tempString;
dataAt += scriptLength; dataAt += scriptLength;
processedBytes += scriptLength; processedBytes += scriptLength;
@ -320,6 +326,7 @@ void Particle::debugDump() const {
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);
printf(" color:%d,%d,%d\n", _color[0], _color[1], _color[2]);
} }
bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details, bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details,
@ -472,7 +479,7 @@ void Particle::update() {
const float REALLY_OLD = 30.0f; // 30 seconds 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 = getShouldDie() || (!isInHand && !isStillMoving && isReallyOld);
setShouldDie(shouldDie); setShouldDie(shouldDie);
const bool wantDebug = false; const bool wantDebug = false;
@ -483,7 +490,7 @@ void Particle::update() {
debug::valueOf(isReallyOld), debug::valueOf(shouldDie)); debug::valueOf(isReallyOld), debug::valueOf(shouldDie));
} }
runScript(); // allow the javascript to alter our state runUpdateScript(); // 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
if (!isInHand) { if (!isInHand) {
@ -507,11 +514,9 @@ void Particle::update() {
_lastUpdated = now; _lastUpdated = now;
} }
void Particle::runScript() { void Particle::runUpdateScript() {
if (!_updateScript.isEmpty()) { if (!_script.isEmpty()) {
//qDebug() << "Script: " << _updateScript << "\n";
QScriptEngine engine; QScriptEngine engine;
// register meta-type for glm::vec3 and rgbColor conversions // register meta-type for glm::vec3 and rgbColor conversions
@ -524,9 +529,9 @@ void Particle::runScript() {
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
engine.globalObject().setProperty("TREE_SCALE", TREE_SCALE); engine.globalObject().setProperty("TREE_SCALE", TREE_SCALE);
//qDebug() << "Downloaded script:" << _updateScript << "\n"; QScriptValue result = engine.evaluate(_script);
QScriptValue result = engine.evaluate(_updateScript);
//qDebug() << "Evaluated script.\n"; particleScriptable.emitUpdate();
if (engine.hasUncaughtException()) { if (engine.hasUncaughtException()) {
int line = engine.uncaughtExceptionLineNumber(); int line = engine.uncaughtExceptionLineNumber();
@ -535,6 +540,100 @@ void Particle::runScript() {
} }
} }
void Particle::collisionWithParticle(Particle* other) {
if (!_script.isEmpty()) {
QScriptEngine engine;
// register meta-type for glm::vec3 and rgbColor conversions
registerMetaTypes(&engine);
ParticleScriptObject particleScriptable(this);
QScriptValue particleValue = engine.newQObject(&particleScriptable);
engine.globalObject().setProperty("Particle", particleValue);
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
engine.globalObject().setProperty("TREE_SCALE", TREE_SCALE);
if (getVoxelsScriptingInterface()) {
QScriptValue voxelScripterValue = engine.newQObject(getVoxelsScriptingInterface());
engine.globalObject().setProperty("Voxels", voxelScripterValue);
}
if (getParticlesScriptingInterface()) {
QScriptValue particleScripterValue = engine.newQObject(getParticlesScriptingInterface());
engine.globalObject().setProperty("Particles", particleScripterValue);
}
QScriptValue result = engine.evaluate(_script);
ParticleScriptObject otherParticleScriptable(other);
particleScriptable.emitCollisionWithParticle(&otherParticleScriptable);
if (getVoxelsScriptingInterface()) {
getVoxelsScriptingInterface()->getPacketSender()->releaseQueuedMessages();
}
if (getParticlesScriptingInterface()) {
getParticlesScriptingInterface()->getPacketSender()->releaseQueuedMessages();
}
if (engine.hasUncaughtException()) {
int line = engine.uncaughtExceptionLineNumber();
qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
}
}
}
void Particle::collisionWithVoxel(VoxelDetail* voxelDetails) {
if (!_script.isEmpty()) {
QScriptEngine engine;
// register meta-type for glm::vec3 and rgbColor conversions
registerMetaTypes(&engine);
ParticleScriptObject particleScriptable(this);
QScriptValue particleValue = engine.newQObject(&particleScriptable);
engine.globalObject().setProperty("Particle", particleValue);
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
engine.globalObject().setProperty("TREE_SCALE", TREE_SCALE);
if (getVoxelsScriptingInterface()) {
QScriptValue voxelScripterValue = engine.newQObject(getVoxelsScriptingInterface());
engine.globalObject().setProperty("Voxels", voxelScripterValue);
}
if (getParticlesScriptingInterface()) {
QScriptValue particleScripterValue = engine.newQObject(getParticlesScriptingInterface());
engine.globalObject().setProperty("Particles", particleScripterValue);
}
QScriptValue result = engine.evaluate(_script);
VoxelDetailScriptObject voxelDetailsScriptable(voxelDetails);
particleScriptable.emitCollisionWithVoxel(&voxelDetailsScriptable);
if (getVoxelsScriptingInterface()) {
getVoxelsScriptingInterface()->getPacketSender()->releaseQueuedMessages();
}
if (getParticlesScriptingInterface()) {
getParticlesScriptingInterface()->getPacketSender()->releaseQueuedMessages();
}
if (engine.hasUncaughtException()) {
int line = engine.uncaughtExceptionLineNumber();
qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
}
}
}
void Particle::setLifetime(float lifetime) { void Particle::setLifetime(float lifetime) {
uint64_t lifetimeInUsecs = lifetime * USECS_PER_SECOND; uint64_t lifetimeInUsecs = lifetime * USECS_PER_SECOND;
_created = usecTimestampNow() - lifetimeInUsecs; _created = usecTimestampNow() - lifetimeInUsecs;

View file

@ -19,6 +19,10 @@
#include <SharedUtil.h> #include <SharedUtil.h>
#include <OctreePacketData.h> #include <OctreePacketData.h>
class VoxelsScriptingInterface;
class ParticlesScriptingInterface;
const uint32_t NEW_PARTICLE = 0xFFFFFFFF; const uint32_t NEW_PARTICLE = 0xFFFFFFFF;
const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF; const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF;
@ -79,7 +83,7 @@ public:
float getEditedAgo() const { return (float)(usecTimestampNow() - _lastEdited) / (float)USECS_PER_SECOND; } float getEditedAgo() const { return (float)(usecTimestampNow() - _lastEdited) / (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 getScript() const { return _script; }
uint32_t getCreatorTokenID() const { return _creatorTokenID; } uint32_t getCreatorTokenID() const { return _creatorTokenID; }
bool isNewlyCreated() const { return _newlyCreated; } bool isNewlyCreated() const { return _newlyCreated; }
@ -96,7 +100,7 @@ public:
void setInHand(bool inHand) { _inHand = inHand; } void setInHand(bool inHand) { _inHand = inHand; }
void setDamping(float value) { _damping = value; } void setDamping(float value) { _damping = value; }
void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; } void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; }
void setUpdateScript(QString updateScript) { _updateScript = updateScript; } void setScript(QString updateScript) { _script = updateScript; }
void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; } void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; }
bool appendParticleData(OctreePacketData* packetData) const; bool appendParticleData(OctreePacketData* packetData) const;
@ -110,14 +114,28 @@ public:
static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew); static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew);
void update(); void update();
void collisionWithParticle(Particle* other);
void collisionWithVoxel(VoxelDetail* voxel);
void debugDump() const; void debugDump() const;
// similar to assignment/copy, but it handles keeping lifetime accurate // similar to assignment/copy, but it handles keeping lifetime accurate
void copyChangedProperties(const Particle& other); void copyChangedProperties(const Particle& other);
static VoxelsScriptingInterface* getVoxelsScriptingInterface() { return _voxelsScriptingInterface; }
static ParticlesScriptingInterface* getParticlesScriptingInterface() { return _particlesScriptingInterface; }
static void setVoxelsScriptingInterface(VoxelsScriptingInterface* interface)
{ _voxelsScriptingInterface = interface; }
static void setParticlesScriptingInterface(ParticlesScriptingInterface* interface)
{ _particlesScriptingInterface = interface; }
protected: protected:
void runScript(); static VoxelsScriptingInterface* _voxelsScriptingInterface;
static ParticlesScriptingInterface* _particlesScriptingInterface;
void runUpdateScript();
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);
@ -134,7 +152,7 @@ protected:
bool _shouldDie; bool _shouldDie;
glm::vec3 _gravity; glm::vec3 _gravity;
float _damping; float _damping;
QString _updateScript; QString _script;
bool _inHand; bool _inHand;
uint32_t _creatorTokenID; uint32_t _creatorTokenID;
@ -152,7 +170,12 @@ class ParticleScriptObject : public QObject {
public: public:
ParticleScriptObject(Particle* particle) { _particle = particle; } ParticleScriptObject(Particle* particle) { _particle = particle; }
void emitUpdate() { emit update(); }
void emitCollisionWithParticle(QObject* other) { emit collisionWithParticle(other); }
void emitCollisionWithVoxel(QObject* voxel) { emit collisionWithVoxel(voxel); }
public slots: public slots:
unsigned int getID() const { return _particle->getID(); }
glm::vec3 getPosition() const { return _particle->getPosition(); } glm::vec3 getPosition() const { return _particle->getPosition(); }
glm::vec3 getVelocity() const { return _particle->getVelocity(); } glm::vec3 getVelocity() const { return _particle->getVelocity(); }
xColor getColor() const { return _particle->getXColor(); } xColor getColor() const { return _particle->getXColor(); }
@ -169,6 +192,12 @@ public slots:
void setColor(xColor value) { _particle->setColor(value); } void setColor(xColor value) { _particle->setColor(value); }
void setRadius(float value) { _particle->setRadius(value); } void setRadius(float value) { _particle->setRadius(value); }
void setShouldDie(bool value) { _particle->setShouldDie(value); } void setShouldDie(bool value) { _particle->setShouldDie(value); }
void setScript(const QString& script) { _particle->setScript(script); }
signals:
void update();
void collisionWithVoxel(QObject* voxel);
void collisionWithParticle(QObject* other);
private: private:
Particle* _particle; Particle* _particle;

View file

@ -73,11 +73,17 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
const float VOXEL_DAMPING = 0.0; const float VOXEL_DAMPING = 0.0;
const float VOXEL_COLLISION_FREQUENCY = 0.5f; const float VOXEL_COLLISION_FREQUENCY = 0.5f;
glm::vec3 penetration; glm::vec3 penetration;
if (_voxels->findSpherePenetration(center, radius, penetration)) { VoxelDetail* voxelDetails = NULL;
if (_voxels->findSpherePenetration(center, radius, penetration, (void**)&voxelDetails)) {
// let the particles run their collision scripts if they have them
particle->collisionWithVoxel(voxelDetails);
penetration /= (float)TREE_SCALE; penetration /= (float)TREE_SCALE;
updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY); updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY);
//qDebug("voxel collision\n");
applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
delete voxelDetails; // cleanup returned details
} }
} }
@ -90,6 +96,11 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) {
glm::vec3 penetration; glm::vec3 penetration;
Particle* penetratedParticle; Particle* penetratedParticle;
if (_particles->findSpherePenetration(center, radius, penetration, (void**)&penetratedParticle)) { if (_particles->findSpherePenetration(center, radius, penetration, (void**)&penetratedParticle)) {
// let the particles run their collision scripts if they have them
particle->collisionWithParticle(penetratedParticle);
penetratedParticle->collisionWithParticle(particle);
penetration /= (float)TREE_SCALE; penetration /= (float)TREE_SCALE;
updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY); updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY);
// apply a hard collision to both particles of half the penetration each // apply a hard collision to both particles of half the penetration each
@ -222,7 +233,7 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::
ParticleEditHandle particleEditHandle(_packetSender, _particles, particle->getID()); ParticleEditHandle particleEditHandle(_packetSender, _particles, particle->getID());
particleEditHandle.updateParticle(position, particle->getRadius(), particle->getXColor(), velocity, particleEditHandle.updateParticle(position, particle->getRadius(), particle->getXColor(), velocity,
particle->getGravity(), particle->getDamping(), particle->getInHand(), particle->getUpdateScript()); particle->getGravity(), particle->getDamping(), particle->getInHand(), particle->getScript());
} }

View file

@ -1,34 +0,0 @@
//
// ParticleScriptingInterface.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 12/6/13
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#include "ParticleScriptingInterface.h"
void ParticleScriptingInterface::queueParticleAdd(PACKET_TYPE addPacketType, ParticleDetail& addParticleDetails) {
getParticlePacketSender()->queueParticleEditMessages(addPacketType, 1, &addParticleDetails);
}
unsigned int ParticleScriptingInterface::queueParticleAdd(glm::vec3 position, float radius,
xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString updateScript) {
// The application will keep track of creatorTokenID
uint32_t creatorTokenID = _nextCreatorTokenID;
_nextCreatorTokenID++;
// setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow();
ParticleDetail addParticleDetail = { NEW_PARTICLE, now,
position, radius, {color.red, color.green, color.blue }, velocity,
gravity, damping, inHand, updateScript, creatorTokenID };
// queue the packet
queueParticleAdd(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail);
return creatorTokenID;
}

View file

@ -0,0 +1,48 @@
//
// ParticlesScriptingInterface.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 12/6/13
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#include "ParticlesScriptingInterface.h"
void ParticlesScriptingInterface::queueParticleMessage(PACKET_TYPE packetType, ParticleDetail& particleDetails) {
getParticlePacketSender()->queueParticleEditMessages(packetType, 1, &particleDetails);
}
unsigned int ParticlesScriptingInterface::queueParticleAdd(glm::vec3 position, float radius,
xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString script) {
// The application will keep track of creatorTokenID
uint32_t creatorTokenID = _nextCreatorTokenID;
_nextCreatorTokenID++;
// setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow();
ParticleDetail addParticleDetail = { NEW_PARTICLE, now,
position, radius, {color.red, color.green, color.blue }, velocity,
gravity, damping, inHand, script, creatorTokenID };
// queue the packet
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail);
return creatorTokenID;
}
void ParticlesScriptingInterface::queueParticleEdit(unsigned int particleID, glm::vec3 position, float radius,
xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString script) {
// setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow();
ParticleDetail editParticleDetail = { particleID, now,
position, radius, {color.red, color.green, color.blue }, velocity,
gravity, damping, inHand, script, UNKNOWN_TOKEN };
// queue the packet
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, editParticleDetail);
}

View file

@ -1,13 +1,13 @@
// //
// ParticleScriptingInterface.h // ParticlesScriptingInterface.h
// hifi // hifi
// //
// Created by Brad Hefta-Gaub on 12/6/13 // Created by Brad Hefta-Gaub on 12/6/13
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
// //
#ifndef __hifi__ParticleScriptingInterface__ #ifndef __hifi__ParticlesScriptingInterface__
#define __hifi__ParticleScriptingInterface__ #define __hifi__ParticlesScriptingInterface__
#include <QtCore/QObject> #include <QtCore/QObject>
@ -16,7 +16,7 @@
#include "ParticleEditPacketSender.h" #include "ParticleEditPacketSender.h"
/// handles scripting of Particle commands from JS passed to assigned clients /// handles scripting of Particle commands from JS passed to assigned clients
class ParticleScriptingInterface : public OctreeScriptingInterface { class ParticlesScriptingInterface : public OctreeScriptingInterface {
Q_OBJECT Q_OBJECT
public: public:
ParticleEditPacketSender* getParticlePacketSender() const { return (ParticleEditPacketSender*)getPacketSender(); } ParticleEditPacketSender* getParticlePacketSender() const { return (ParticleEditPacketSender*)getPacketSender(); }
@ -27,12 +27,15 @@ public slots:
/// queues the creation of a Particle which will be sent by calling process on the PacketSender /// queues the creation of a Particle which will be sent by calling process on the PacketSender
/// returns the creatorTokenID for the newly created particle /// returns the creatorTokenID for the newly created particle
unsigned int queueParticleAdd(glm::vec3 position, float radius, unsigned int queueParticleAdd(glm::vec3 position, float radius,
xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString updateScript); xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString script);
void queueParticleEdit(unsigned int particleID, glm::vec3 position, float radius,
xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString script);
private: private:
void queueParticleAdd(PACKET_TYPE addPacketType, ParticleDetail& addParticleDetails); void queueParticleMessage(PACKET_TYPE packetType, ParticleDetail& particleDetails);
uint32_t _nextCreatorTokenID; uint32_t _nextCreatorTokenID;
}; };
#endif /* defined(__hifi__ParticleScriptingInterface__) */ #endif /* defined(__hifi__ParticlesScriptingInterface__) */

View file

@ -1,5 +1,5 @@
// //
// Agent.cpp // ScriptEngine.cpp
// hifi // hifi
// //
// Created by Brad Hefta-Gaub on 12/14/13. // Created by Brad Hefta-Gaub on 12/14/13.
@ -23,6 +23,9 @@
#include "ScriptEngine.h" #include "ScriptEngine.h"
int ScriptEngine::_scriptNumber = 1; int ScriptEngine::_scriptNumber = 1;
VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface;
ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface;
ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems,
const char* scriptMenuName, AbstractMenuInterface* menu, const char* scriptMenuName, AbstractMenuInterface* menu,
@ -43,6 +46,15 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems,
} }
_menu = menu; _menu = menu;
_controllerScriptingInterface = controllerScriptingInterface; _controllerScriptingInterface = controllerScriptingInterface;
// hook up our interfaces
if (!Particle::getVoxelsScriptingInterface()) {
Particle::setVoxelsScriptingInterface(getVoxelsScriptingInterface());
}
if (!Particle::getParticlesScriptingInterface()) {
Particle::setParticlesScriptingInterface(getParticlesScriptingInterface());
}
} }
ScriptEngine::~ScriptEngine() { ScriptEngine::~ScriptEngine() {
@ -74,8 +86,8 @@ void ScriptEngine::run() {
_isRunning = true; _isRunning = true;
QScriptEngine engine; QScriptEngine engine;
_voxelScriptingInterface.init(); _voxelsScriptingInterface.init();
_particleScriptingInterface.init(); _particlesScriptingInterface.init();
// register meta-type for glm::vec3 conversions // register meta-type for glm::vec3 conversions
registerMetaTypes(&engine); registerMetaTypes(&engine);
@ -83,10 +95,10 @@ void ScriptEngine::run() {
QScriptValue agentValue = engine.newQObject(this); QScriptValue agentValue = engine.newQObject(this);
engine.globalObject().setProperty("Agent", agentValue); engine.globalObject().setProperty("Agent", agentValue);
QScriptValue voxelScripterValue = engine.newQObject(&_voxelScriptingInterface); QScriptValue voxelScripterValue = engine.newQObject(&_voxelsScriptingInterface);
engine.globalObject().setProperty("Voxels", voxelScripterValue); engine.globalObject().setProperty("Voxels", voxelScripterValue);
QScriptValue particleScripterValue = engine.newQObject(&_particleScriptingInterface); QScriptValue particleScripterValue = engine.newQObject(&_particlesScriptingInterface);
engine.globalObject().setProperty("Particles", particleScripterValue); engine.globalObject().setProperty("Particles", particleScripterValue);
if (_controllerScriptingInterface) { if (_controllerScriptingInterface) {
@ -100,8 +112,8 @@ void ScriptEngine::run() {
const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000;
// let the VoxelPacketSender know how frequently we plan to call it // let the VoxelPacketSender know how frequently we plan to call it
_voxelScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); _voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS);
_particleScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); _particlesScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS);
//qDebug() << "Script:\n" << _scriptContents << "\n"; //qDebug() << "Script:\n" << _scriptContents << "\n";
@ -135,29 +147,29 @@ void ScriptEngine::run() {
} }
bool willSendVisualDataCallBack = false; bool willSendVisualDataCallBack = false;
if (_voxelScriptingInterface.getVoxelPacketSender()->serversExist()) { if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) {
// allow the scripter's call back to setup visual data // allow the scripter's call back to setup visual data
willSendVisualDataCallBack = true; willSendVisualDataCallBack = true;
// release the queue of edit voxel messages. // release the queue of edit voxel messages.
_voxelScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages(); _voxelsScriptingInterface.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
if (!_voxelScriptingInterface.getVoxelPacketSender()->isThreaded()) { if (!_voxelsScriptingInterface.getVoxelPacketSender()->isThreaded()) {
_voxelScriptingInterface.getVoxelPacketSender()->process(); _voxelsScriptingInterface.getVoxelPacketSender()->process();
} }
} }
if (_particleScriptingInterface.getParticlePacketSender()->serversExist()) { if (_particlesScriptingInterface.getParticlePacketSender()->serversExist()) {
// allow the scripter's call back to setup visual data // allow the scripter's call back to setup visual data
willSendVisualDataCallBack = true; willSendVisualDataCallBack = true;
// release the queue of edit voxel messages. // release the queue of edit voxel messages.
_particleScriptingInterface.getParticlePacketSender()->releaseQueuedMessages(); _particlesScriptingInterface.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
if (!_particleScriptingInterface.getParticlePacketSender()->isThreaded()) { if (!_particlesScriptingInterface.getParticlePacketSender()->isThreaded()) {
_particleScriptingInterface.getParticlePacketSender()->process(); _particlesScriptingInterface.getParticlePacketSender()->process();
} }
} }

View file

@ -16,8 +16,8 @@
#include <QtCore/QUrl> #include <QtCore/QUrl>
#include <AbstractMenuInterface.h> #include <AbstractMenuInterface.h>
#include <ParticleScriptingInterface.h> #include <ParticlesScriptingInterface.h>
#include <VoxelScriptingInterface.h> #include <VoxelsScriptingInterface.h>
#include "AbstractControllerScriptingInterface.h" #include "AbstractControllerScriptingInterface.h"
const QString NO_SCRIPT(""); const QString NO_SCRIPT("");
@ -31,11 +31,11 @@ public:
~ScriptEngine(); ~ScriptEngine();
/// Access the VoxelScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener /// Access the VoxelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
VoxelScriptingInterface* getVoxelScriptingInterface() { return &_voxelScriptingInterface; } VoxelsScriptingInterface* getVoxelsScriptingInterface() { return &_voxelsScriptingInterface; }
/// Access the ParticleScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener /// Access the ParticlesScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
ParticleScriptingInterface* getParticleScriptingInterface() { return &_particleScriptingInterface; } ParticlesScriptingInterface* getParticlesScriptingInterface() { return &_particlesScriptingInterface; }
/// sets the script contents, will return false if failed, will fail if script is already running /// sets the script contents, will return false if failed, will fail if script is already running
bool setScriptContents(const QString& scriptContents); bool setScriptContents(const QString& scriptContents);
@ -58,8 +58,8 @@ protected:
private: private:
VoxelScriptingInterface _voxelScriptingInterface; static VoxelsScriptingInterface _voxelsScriptingInterface;
ParticleScriptingInterface _particleScriptingInterface; static ParticlesScriptingInterface _particlesScriptingInterface;
AbstractControllerScriptingInterface* _controllerScriptingInterface; AbstractControllerScriptingInterface* _controllerScriptingInterface;
bool _wantMenuItems; bool _wantMenuItems;
QString _scriptMenuName; QString _scriptMenuName;

View file

@ -239,3 +239,26 @@ bool VoxelTreeElement::collapseChildren() {
return allChildrenMatch; return allChildrenMatch;
} }
bool VoxelTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const {
if (_box.findSpherePenetration(center, radius, penetration)) {
// if the caller wants details about the voxel, then return them here...
if (penetratedObject) {
VoxelDetail* voxelDetails = new VoxelDetail;
voxelDetails->x = _box.getCorner().x;
voxelDetails->y = _box.getCorner().y;
voxelDetails->z = _box.getCorner().z;
voxelDetails->s = _box.getScale();
voxelDetails->red = getTrueColor()[RED_INDEX];
voxelDetails->green = getTrueColor()[GREEN_INDEX];
voxelDetails->blue = getTrueColor()[BLUE_INDEX];
*penetratedObject = (void*)voxelDetails;
}
return true;
}
return false;
}

View file

@ -44,6 +44,9 @@ public:
virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
virtual void calculateAverageFromChildren(); virtual void calculateAverageFromChildren();
virtual bool collapseChildren(); virtual bool collapseChildren();
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const;
glBufferIndex getBufferIndex() const { return _glBufferIndex; } glBufferIndex getBufferIndex() const { return _glBufferIndex; }
@ -88,4 +91,5 @@ protected:
nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes
}; };
#endif /* defined(__hifi__VoxelTreeElement__) */ #endif /* defined(__hifi__VoxelTreeElement__) */

View file

@ -1,18 +1,18 @@
// //
// VoxelScriptingInterface.cpp // VoxelsScriptingInterface.cpp
// hifi // hifi
// //
// Created by Stephen Birarda on 9/17/13. // Created by Stephen Birarda on 9/17/13.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
// //
#include "VoxelScriptingInterface.h" #include "VoxelsScriptingInterface.h"
void VoxelScriptingInterface::queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDetail& addVoxelDetails) { void VoxelsScriptingInterface::queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDetail& addVoxelDetails) {
getVoxelPacketSender()->queueVoxelEditMessages(addPacketType, 1, &addVoxelDetails); getVoxelPacketSender()->queueVoxelEditMessages(addPacketType, 1, &addVoxelDetails);
} }
void VoxelScriptingInterface::queueVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) { void VoxelsScriptingInterface::queueVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) {
// setup a VoxelDetail struct with the data // setup a VoxelDetail struct with the data
VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue};
@ -20,7 +20,7 @@ void VoxelScriptingInterface::queueVoxelAdd(float x, float y, float z, float sca
queueVoxelAdd(PACKET_TYPE_VOXEL_SET, addVoxelDetail); queueVoxelAdd(PACKET_TYPE_VOXEL_SET, addVoxelDetail);
} }
void VoxelScriptingInterface::queueDestructiveVoxelAdd(float x, float y, float z, float scale, void VoxelsScriptingInterface::queueDestructiveVoxelAdd(float x, float y, float z, float scale,
uchar red, uchar green, uchar blue) { uchar red, uchar green, uchar blue) {
// setup a VoxelDetail struct with the data // setup a VoxelDetail struct with the data
VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue};
@ -29,7 +29,7 @@ void VoxelScriptingInterface::queueDestructiveVoxelAdd(float x, float y, float z
queueVoxelAdd(PACKET_TYPE_VOXEL_SET_DESTRUCTIVE, addVoxelDetail); queueVoxelAdd(PACKET_TYPE_VOXEL_SET_DESTRUCTIVE, addVoxelDetail);
} }
void VoxelScriptingInterface::queueVoxelDelete(float x, float y, float z, float scale) { void VoxelsScriptingInterface::queueVoxelDelete(float x, float y, float z, float scale) {
// setup a VoxelDetail struct with data // setup a VoxelDetail struct with data
VoxelDetail deleteVoxelDetail = {x, y, z, scale, 0, 0, 0}; VoxelDetail deleteVoxelDetail = {x, y, z, scale, 0, 0, 0};

View file

@ -1,13 +1,13 @@
// //
// VoxelScriptingInterface.h // VoxelsScriptingInterface.h
// hifi // hifi
// //
// Created by Stephen Birarda on 9/17/13. // Created by Stephen Birarda on 9/17/13.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
// //
#ifndef __hifi__VoxelScriptingInterface__ #ifndef __hifi__VoxelsScriptingInterface__
#define __hifi__VoxelScriptingInterface__ #define __hifi__VoxelsScriptingInterface__
#include <QtCore/QObject> #include <QtCore/QObject>
@ -16,7 +16,7 @@
#include "VoxelEditPacketSender.h" #include "VoxelEditPacketSender.h"
/// handles scripting of voxel commands from JS passed to assigned clients /// handles scripting of voxel commands from JS passed to assigned clients
class VoxelScriptingInterface : public OctreeScriptingInterface { class VoxelsScriptingInterface : public OctreeScriptingInterface {
Q_OBJECT Q_OBJECT
public: public:
VoxelEditPacketSender* getVoxelPacketSender() { return (VoxelEditPacketSender*)getPacketSender(); } VoxelEditPacketSender* getVoxelPacketSender() { return (VoxelEditPacketSender*)getPacketSender(); }
@ -56,4 +56,18 @@ private:
void queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDetail& addVoxelDetails); void queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDetail& addVoxelDetails);
}; };
#endif /* defined(__hifi__VoxelScriptingInterface__) */ class VoxelDetailScriptObject : public QObject {
Q_OBJECT
public:
VoxelDetailScriptObject(VoxelDetail* voxelDetail) { _voxelDetail = voxelDetail; }
public slots:
glm::vec3 getPosition() const { return glm::vec3(_voxelDetail->x, _voxelDetail->y, _voxelDetail->z); }
xColor getColor() const { return { _voxelDetail->red, _voxelDetail->green, _voxelDetail->blue }; }
float getScale() const { return _voxelDetail->s; }
private:
VoxelDetail* _voxelDetail;
};
#endif /* defined(__hifi__VoxelsScriptingInterface__) */