Merge remote-tracking branch 'upstream/master' into oculus

This commit is contained in:
Stephen Birarda 2013-05-10 14:00:10 -07:00
commit 9ee3f889ab
14 changed files with 433 additions and 184 deletions

View file

@ -144,6 +144,8 @@ int main(int argc, const char* argv[]) {
float weakChannelAmplitudeRatio = 1.f;
if (otherAgent != agent) {
printf("DEBUG: The bearing for this agent is %f\n", agentRingBuffer->getBearing());
Position agentPosition = agentRingBuffer->getPosition();
Position otherAgentPosition = otherAgentBuffer->getPosition();

View file

@ -55,6 +55,12 @@ if (APPLE)
SET(INTERFACE_SRCS ${INTERFACE_SRCS} ${INTERFACE_RSRCS})
endif (APPLE)
find_package(Qt4 REQUIRED QtCore QtGui)
include(${QT_USE_FILE})
# run qt moc on qt-enabled headers
qt4_wrap_cpp(INTERFACE_SRCS src/Application.h)
# create the executable, make it a bundle on OS X
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS})

View file

@ -0,0 +1,22 @@
//
// Application.cpp
// interface
//
// Created by Andrzej Kapolka on 5/10/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <QMenuBar>
#include <QtDebug>
#include "Application.h"
Application::Application(int& argc, char** argv) : QApplication(argc, argv) {
// simple menu bar (will only appear on OS X, for now)
QMenuBar* menuBar = new QMenuBar();
QMenu* fileMenu = menuBar->addMenu("File");
fileMenu->addAction("Test", this, SLOT(testSlot()));
}
void Application::testSlot() {
qDebug() << "Hello world.";
}

View file

@ -0,0 +1,26 @@
//
// Application.h
// interface
//
// Created by Andrzej Kapolka on 5/10/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__Application__
#define __interface__Application__
#include <QApplication>
class Application : public QApplication {
Q_OBJECT
public:
Application(int& argc, char** argv);
public slots:
void testSlot();
};
#endif /* defined(__interface__Application__) */

View file

@ -516,37 +516,46 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
}
}
}
glm::vec3 vectorFromMyHandToYourHand
(
_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position -
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position
);
float distanceBetweenOurHands = glm::length(vectorFromMyHandToYourHand);
/*
// if my arm can no longer reach the other hand, turn off hand-holding
if (!_avatarTouch.getAbleToReachOtherAvatar()) {
_avatarTouch.setHoldingHands(false);
}
if (distanceBetweenOurHands > _maxArmLength) {
_avatarTouch.setHoldingHands(false);
}
*/
// if neither of us are grasping, turn off hand-holding
if ((_handState != HAND_STATE_GRASPING ) && (_interactingOther->_handState != HAND_STATE_GRASPING)) {
_avatarTouch.setHoldingHands(false);
}
}
//if holding hands, apply the appropriate forces
if (_avatarTouch.getHoldingHands()) {
glm::vec3 vectorToOtherHand = _interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition - _handHoldingPosition;
glm::vec3 vectorToMyHand = _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - _handHoldingPosition;
float myInfluence = 30.0f;
float yourInfluence = 30.0f;
glm::vec3 myForce = vectorToMyHand * myInfluence * deltaTime;
glm::vec3 yourForce = vectorToOtherHand * yourInfluence * deltaTime;
if (_handState == HAND_STATE_GRASPING) {myForce *= 2.0f; }
if (_interactingOther->_handState == HAND_STATE_GRASPING) {yourForce *= 2.0f; }
//if holding hands, apply the appropriate forces
if (_avatarTouch.getHoldingHands()) {
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position +=
(
_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position
- _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position
) * 0.5f;
_handHoldingPosition += myForce + yourForce;
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handHoldingPosition;
} else {
_handHoldingPosition = _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position;
}
if (distanceBetweenOurHands > 0.2) {
float force = 700.0f * deltaTime;
if (force > 1.0f) {force = 1.0f;}
_velocity += vectorFromMyHandToYourHand * force;
}
}
}
}//if (_isMine)
//constrain right arm length and re-adjust elbow position as it bends
@ -1262,7 +1271,7 @@ void Avatar::initializeSkeleton() {
_joint[ AVATAR_JOINT_LEFT_HEEL ].radius +
_joint[ AVATAR_JOINT_LEFT_HEEL ].length +
_joint[ AVATAR_JOINT_LEFT_KNEE ].length;
printf("_pelvisStandingHeight = %f\n", _pelvisStandingHeight);
//printf("_pelvisStandingHeight = %f\n", _pelvisStandingHeight);
_height =
(
@ -1277,7 +1286,7 @@ void Avatar::initializeSkeleton() {
_joint[ AVATAR_JOINT_HEAD_BASE ].length +
_joint[ AVATAR_JOINT_HEAD_BASE ].radius
);
printf("_height = %f\n", _height);
//printf("_height = %f\n", _height);
// generate joint positions by updating the skeleton
updateSkeleton();

View file

@ -12,21 +12,20 @@
#include "InterfaceConfig.h"
#include "Util.h"
const float THREAD_RADIUS = 0.012;
const float HANDS_CLOSE_ENOUGH_TO_GRASP = 0.1;
const float THREAD_RADIUS = 0.007;
const float HANDS_CLOSE_ENOUGH_TO_GRASP = 0.2;
AvatarTouch::AvatarTouch() {
_myHandPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_yourHandPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_myBodyPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_yourBodyPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_vectorBetweenHands = glm::vec3(0.0f, 0.0f, 0.0f);
_myHandState = HAND_STATE_NULL;
_yourHandState = HAND_STATE_NULL;
_reachableRadius = 0.0f;
_weAreHoldingHands = false;
_myHandPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_yourHandPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_myBodyPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_yourBodyPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_vectorBetweenHands = glm::vec3(0.0f, 0.0f, 0.0f);
_myHandState = HAND_STATE_NULL;
_yourHandState = HAND_STATE_NULL;
_reachableRadius = 0.0f;
_weAreHoldingHands = false;
_canReachToOtherAvatar = false;
_handsCloseEnoughToGrasp = false;
@ -63,7 +62,6 @@ void AvatarTouch::setReachableRadius(float r) {
_reachableRadius = r;
}
void AvatarTouch::simulate (float deltaTime) {
glm::vec3 vectorBetweenBodies = _yourBodyPosition - _myBodyPosition;
@ -83,9 +81,7 @@ void AvatarTouch::simulate (float deltaTime) {
} else {
_canReachToOtherAvatar = false;
}
}
}
void AvatarTouch::render(glm::vec3 cameraPosition) {
@ -99,6 +95,18 @@ void AvatarTouch::render(glm::vec3 cameraPosition) {
// show is we are golding hands...
if (_weAreHoldingHands) {
renderBeamBetweenHands();
/*
glPushMatrix();
glTranslatef(_yourHandPosition.x, _yourHandPosition.y, _yourHandPosition.z);
glColor4f(1.0, 0.0, 0.0, 0.7); glutSolidSphere(0.020f, 10.0f, 10.0f);
glColor4f(1.0, 0.0, 0.0, 0.7); glutSolidSphere(0.025f, 10.0f, 10.0f);
glColor4f(1.0, 0.0, 0.0, 0.7); glutSolidSphere(0.030f, 10.0f, 10.0f);
glPopMatrix();
*/
/*
glColor4f(0.9, 0.3, 0.3, 0.5);
renderSphereOutline(_myHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.3f, 20, cameraPosition);
renderSphereOutline(_myHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.2f, 20, cameraPosition);
@ -107,24 +115,23 @@ void AvatarTouch::render(glm::vec3 cameraPosition) {
renderSphereOutline(_yourHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.3f, 20, cameraPosition);
renderSphereOutline(_yourHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.2f, 20, cameraPosition);
renderSphereOutline(_yourHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.1f, 20, cameraPosition);
*/
}
//render the beam between our hands indicting that we can reach out and grasp hands...
renderBeamBetweenHands();
//show that our hands are close enough to grasp..
if (_handsCloseEnoughToGrasp) {
glColor4f(0.9, 0.3, 0.3, 0.5);
renderSphereOutline(_myHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP / 3.0f, 20, cameraPosition);
renderSphereOutline(_myHandPosition, 0.03f, 20, cameraPosition);
renderSphereOutline(_yourHandPosition, 0.03f, 20, cameraPosition);
}
// if your hand is grasping, show it...
if (_yourHandState == HAND_STATE_GRASPING) {
glPushMatrix();
glTranslatef(_yourHandPosition.x, _yourHandPosition.y, _yourHandPosition.z);
glColor4f(1.0, 1.0, 0.8, 0.3); glutSolidSphere(0.020f, 10.0f, 10.0f);
glColor4f(1.0, 1.0, 0.4, 0.2); glutSolidSphere(0.025f, 10.0f, 10.0f);
glColor4f(1.0, 1.0, 0.2, 0.1); glutSolidSphere(0.030f, 10.0f, 10.0f);
glColor4f(1.0, 0.7, 0.8, 0.4); glutSolidSphere(0.020f, 10.0f, 10.0f);
glColor4f(1.0, 0.7, 0.4, 0.3); glutSolidSphere(0.025f, 10.0f, 10.0f);
glColor4f(1.0, 0.7, 0.2, 0.2); glutSolidSphere(0.030f, 10.0f, 10.0f);
glPopMatrix();
}
}
@ -133,9 +140,9 @@ void AvatarTouch::render(glm::vec3 cameraPosition) {
if (_myHandState == HAND_STATE_GRASPING) {
glPushMatrix();
glTranslatef(_myHandPosition.x, _myHandPosition.y, _myHandPosition.z);
glColor4f(1.0, 1.0, 0.8, 0.3); glutSolidSphere(0.020f, 10.0f, 10.0f);
glColor4f(1.0, 1.0, 0.4, 0.2); glutSolidSphere(0.025f, 10.0f, 10.0f);
glColor4f(1.0, 1.0, 0.2, 0.1); glutSolidSphere(0.030f, 10.0f, 10.0f);
glColor4f(1.0, 0.7, 0.8, 0.4); glutSolidSphere(0.020f, 10.0f, 10.0f);
glColor4f(1.0, 0.7, 0.4, 0.3); glutSolidSphere(0.025f, 10.0f, 10.0f);
glColor4f(1.0, 0.7, 0.2, 0.2); glutSolidSphere(0.030f, 10.0f, 10.0f);
glPopMatrix();
}
}
@ -147,14 +154,14 @@ void AvatarTouch::renderBeamBetweenHands() {
glm::vec3 v1(_myHandPosition);
glm::vec3 v2(_yourHandPosition);
glLineWidth(2.0);
glColor4f(0.9f, 0.9f, 0.1f, 0.7);
glLineWidth(3.0);
glColor4f(0.9f, 0.9f, 0.1f, 0.6);
glBegin(GL_LINE_STRIP);
glVertex3f(v1.x, v1.y, v1.z);
glVertex3f(v2.x, v2.y, v2.z);
glEnd();
glColor3f(1.0f, 1.0f, 1.0f);
glColor3f(0.5f, 0.3f, 0.0f);
for (int p=0; p<NUM_POINTS; p++) {
_point[p] = _myHandPosition + _vectorBetweenHands * ((float)p / (float)NUM_POINTS);

View file

@ -32,7 +32,7 @@
#define HEAD_YAW_RATE 0
#define HEAD_ROLL_RATE 2
//const bool USING_INVENSENSE_MPU9150;
extern const bool USING_INVENSENSE_MPU9150;
class SerialInterface {
public:

View file

@ -205,17 +205,86 @@ void VoxelSystem::cleanupRemovedVoxels() {
}
}
void VoxelSystem::copyWrittenDataToReadArraysFullVBOs() {
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
pthread_mutex_lock(&_bufferWriteLock);
int bytesOfVertices = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat);
int bytesOfColors = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte);
memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices);
memcpy(_readColorsArray, _writeColorsArray, bytesOfColors );
_voxelsInReadArrays = _voxelsInWriteArrays;
pthread_mutex_unlock(&_bufferWriteLock);
}
void VoxelSystem::copyWrittenDataToReadArraysPartialVBOs() {
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
pthread_mutex_lock(&_bufferWriteLock);
glBufferIndex segmentStart = 0;
glBufferIndex segmentEnd = 0;
bool inSegment = false;
for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) {
bool thisVoxelDirty = _voxelDirtyArray[i];
if (!inSegment) {
if (thisVoxelDirty) {
segmentStart = i;
inSegment = true;
}
} else {
if (!thisVoxelDirty) {
// If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before
// this one and so that's where the "segment" ends
segmentEnd = i - 1;
inSegment = false;
int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes);
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
memcpy(readColorsAt, writeColorsAt, segmentSizeBytes);
}
}
}
// if we got to the end of the array, and we're in an active dirty segment...
if (inSegment) {
segmentEnd = _voxelsInWriteArrays - 1;
int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes);
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
memcpy(readColorsAt, writeColorsAt, segmentSizeBytes);
}
// update our length
_voxelsInReadArrays = _voxelsInWriteArrays;
pthread_mutex_unlock(&_bufferWriteLock);
}
void VoxelSystem::copyWrittenDataToReadArrays() {
PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated
PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()");
if (_voxelsDirty && _voxelsUpdated) {
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
pthread_mutex_lock(&_bufferWriteLock);
int bytesOfVertices = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat);
int bytesOfColors = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte);
memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices);
memcpy(_readColorsArray, _writeColorsArray, bytesOfColors );
_voxelsInReadArrays = _voxelsInWriteArrays;
pthread_mutex_unlock(&_bufferWriteLock);
if (_renderFullVBO) {
copyWrittenDataToReadArraysFullVBOs();
} else {
copyWrittenDataToReadArraysPartialVBOs();
}
}
}
@ -232,7 +301,7 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) {
bool inChildBoundary = (distanceToNode <= childBoundary);
shouldRender = (node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary);
}
node->setShouldRender(shouldRender);
node->setShouldRender(shouldRender && !node->isStagedForDeletion());
// let children figure out their renderness
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
if (node->getChildAtIndex(i)) {
@ -244,6 +313,15 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) {
} else {
voxelsUpdated += updateNodeInArraysAsPartialVBO(node);
}
// If the node has been asked to be deleted, but we've gotten to here, after updateNodeInArraysXXX()
// then it means our VBOs are "clean" and our vertices have been removed or not added. So we can now
// safely remove the node from the tree and actually delete it.
// otherwise honor our calculated shouldRender
if (node->isStagedForDeletion()) {
_tree->deleteVoxelCodeFromTree(node->getOctalCode());
}
node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered
return voxelsUpdated;
}
@ -484,11 +562,10 @@ void VoxelSystem::updateVBOs() {
};
PerformanceWarning warn(_renderWarningsOn, buffer); // would like to include _callsToTreesToArrays
if (_voxelsDirty) {
// updatePartialVBOs() is not yet working. For now, ALWAYS call updateFullVBOs()
if (_renderFullVBO) {
updateFullVBOs();
} else {
updatePartialVBOs(); // too many small segments?
updatePartialVBOs();
}
_voxelsDirty = false;
}
@ -901,9 +978,19 @@ void VoxelSystem::collectStatsForTreesAndVBOs() {
void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) {
//printLog("VoxelSystem::deleteVoxelAt(%f,%f,%f,%f)\n",x,y,z,s);
_tree->deleteVoxelAt(x, y, z, s);
setupNewVoxelsForDrawing();
printLog("VoxelSystem::deleteVoxelAt(%f,%f,%f,%f)\n",x,y,z,s);
VoxelNode* node = _tree->getVoxelAt(x, y, z, s);
if (node) {
// tell the node we want it deleted
node->stageForDeletion();
// tree is now dirty
_tree->setDirtyBit();
// redraw!
setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in?
}
};
VoxelNode* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const {

View file

@ -97,6 +97,9 @@ private:
int updateNodeInArraysAsFullVBO(VoxelNode* node);
int updateNodeInArraysAsPartialVBO(VoxelNode* node);
void copyWrittenDataToReadArraysFullVBOs();
void copyWrittenDataToReadArraysPartialVBOs();
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
static float _maxDistance;
static float _minDistance;

View file

@ -30,8 +30,6 @@
#include <ifaddrs.h>
#endif
#include <QApplication>
#include <pthread.h>
#include <glm/glm.hpp>
@ -62,6 +60,7 @@
#include "renderer/ProgramObject.h"
#include "renderer/ShaderObject.h"
#include "Application.h"
#include "Camera.h"
#include "Avatar.h"
#include <AgentList.h>
@ -88,8 +87,6 @@ void loadViewFrustum(ViewFrustum& viewFrustum); // will be defined below
glm::vec3 getGravity(glm::vec3 pos); //get the local gravity vector at this location in the universe
QApplication* app;
bool enableNetworkThread = true;
pthread_t networkReceiveThread;
bool stopNetworkReceiveThread = false;
@ -177,6 +174,12 @@ int mouseY = 0;
// Mouse location at start of last down click
int mousePressed = 0; // true if mouse has been pressed (clear when finished)
// The current mode for mouse interaction
enum MouseMode { ADD_VOXEL_MODE, DELETE_VOXEL_MODE, COLOR_VOXEL_MODE };
MouseMode mouseMode = ADD_VOXEL_MODE;
VoxelDetail mouseVoxel; // details of the voxel under the mouse cursor
float mouseVoxelScale = 1.0f / 1024.0f; // the scale for adding/removing voxels
Menu menu; // main menu
int menuOn = 1; // Whether to show onscreen menu
@ -356,6 +359,16 @@ void reset_sensors() {
myAvatar.reset();
}
void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
unsigned char* bufferOut;
int sizeOut;
if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1);
delete bufferOut;
}
}
//
// Using gyro data, update both view frustum and avatar head position
//
@ -369,13 +382,14 @@ void updateAvatar(float deltaTime) {
float measuredYawRate = serialPort.getLastYawRate();
// Update gyro-based mouse (X,Y on screen)
const float MIN_MOUSE_RATE = 30.0;
const float MOUSE_SENSITIVITY = 0.1f;
const float MIN_MOUSE_RATE = 1.0;
const float HORIZONTAL_PIXELS_PER_DEGREE = 2880.f / 45.f;
const float VERTICAL_PIXELS_PER_DEGREE = 1800.f / 30.f;
if (powf(measuredYawRate * measuredYawRate +
measuredPitchRate * measuredPitchRate, 0.5) > MIN_MOUSE_RATE)
{
headMouseX += measuredYawRate*MOUSE_SENSITIVITY;
headMouseY += measuredPitchRate*MOUSE_SENSITIVITY*(float)HEIGHT/(float)WIDTH;
headMouseX += measuredYawRate * HORIZONTAL_PIXELS_PER_DEGREE * deltaTime;
headMouseY -= measuredPitchRate * VERTICAL_PIXELS_PER_DEGREE * deltaTime;
}
headMouseX = max(headMouseX, 0);
headMouseX = min(headMouseX, WIDTH);
@ -384,32 +398,17 @@ void updateAvatar(float deltaTime) {
// Update head and body pitch and yaw based on measured gyro rates
if (::gyroLook) {
// Yaw
const float MIN_YAW_RATE = 20.f;
const float YAW_MAGNIFY = 3.0;
// Render Yaw
float renderYawSpring = fabs(headMouseX - WIDTH / 2.f) / (WIDTH / 2.f);
const float RENDER_YAW_MULTIPLY = 4.f;
myAvatar.setRenderYaw((1.f - renderYawSpring * deltaTime) * myAvatar.getRenderYaw() +
renderYawSpring * deltaTime * -myAvatar.getHeadYaw() * RENDER_YAW_MULTIPLY);
// Render Pitch
float renderPitchSpring = fabs(headMouseY - HEIGHT / 2.f) / (HEIGHT / 2.f);
const float RENDER_PITCH_MULTIPLY = 4.f;
myAvatar.setRenderPitch((1.f - renderPitchSpring * deltaTime) * myAvatar.getRenderPitch() +
renderPitchSpring * deltaTime * -myAvatar.getHeadPitch() * RENDER_PITCH_MULTIPLY);
if (fabs(measuredYawRate) > MIN_YAW_RATE) {
float addToBodyYaw = (measuredYawRate > 0.f)
? measuredYawRate - MIN_YAW_RATE : measuredYawRate + MIN_YAW_RATE;
// If we are rotating the body (render angle), move the head reverse amount to compensate
myAvatar.addBodyYaw(-addToBodyYaw * YAW_MAGNIFY * deltaTime);
myAvatar.addHeadYaw(addToBodyYaw * YAW_MAGNIFY * deltaTime);
}
// Pitch
const float MIN_PITCH_RATE = 20.f;
const float PITCH_MAGNIFY = 2.0;
if (fabs(measuredPitchRate) > MIN_PITCH_RATE) {
float addToBodyPitch = (measuredPitchRate > 0.f)
? measuredPitchRate - MIN_PITCH_RATE : measuredPitchRate + MIN_PITCH_RATE;
myAvatar.setRenderPitch(myAvatar.getRenderPitch() + addToBodyPitch * PITCH_MAGNIFY * deltaTime);
}
// Always decay the render pitch, assuming that we are never going to want to permanently look up or down
const float RENDER_PITCH_DECAY = 1.0;
myAvatar.setRenderPitch(myAvatar.getRenderPitch() * (1.f - RENDER_PITCH_DECAY * deltaTime));
}
if (OculusManager::isConnected()) {
@ -467,17 +466,11 @@ void updateAvatar(float deltaTime) {
::paintingVoxel.y = avatarPos.y / 10.0;
::paintingVoxel.z = avatarPos.z / 10.0;
unsigned char* bufferOut;
int sizeOut;
if (::paintingVoxel.x >= 0.0 && ::paintingVoxel.x <= 1.0 &&
::paintingVoxel.y >= 0.0 && ::paintingVoxel.y <= 1.0 &&
::paintingVoxel.z >= 0.0 && ::paintingVoxel.z <= 1.0) {
if (createVoxelEditMessage(PACKET_HEADER_SET_VOXEL, 0, 1, &::paintingVoxel, bufferOut, sizeOut)){
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1);
delete bufferOut;
}
sendVoxelEditMessage(PACKET_HEADER_SET_VOXEL, ::paintingVoxel);
}
}
}
@ -730,6 +723,20 @@ void displaySide(Camera& whichCamera) {
voxels.render();
}
// indicate what we'll be adding/removing in mouse mode, if anything
if (::mouseVoxel.s != 0) {
glPushMatrix();
glColor3ub(::mouseVoxel.red, ::mouseVoxel.green, ::mouseVoxel.blue);
glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE);
glTranslatef(::mouseVoxel.x + ::mouseVoxel.s*0.5f,
::mouseVoxel.y + ::mouseVoxel.s*0.5f,
::mouseVoxel.z + ::mouseVoxel.s*0.5f);
glLineWidth(4.0f);
glutWireCube(::mouseVoxel.s);
glLineWidth(1.0f);
glPopMatrix();
}
if (::renderAvatarsOn) {
// Render avatars of other agents
AgentList* agentList = AgentList::getInstance();
@ -921,7 +928,7 @@ void displayOverlay() {
//noiseTest(WIDTH, HEIGHT);
if (displayHeadMouse && !::lookingInMirror && renderStatsOn) {
if (displayHeadMouse && !::lookingInMirror && USING_INVENSENSE_MPU9150) {
// Display small target box at center or head mouse target that can also be used to measure LOD
glColor3f(1.0, 1.0, 1.0);
glDisable(GL_LINE_SMOOTH);
@ -1436,72 +1443,41 @@ void setupPaintingVoxel() {
shiftPaintingColor();
}
void addVoxelUnderCursor() {
glm::vec3 origin, direction;
viewFrustum.computePickRay(mouseX / (float)WIDTH, mouseY / (float)HEIGHT, origin, direction);
void addVoxelInFrontOfAvatar() {
VoxelDetail detail;
float distance;
BoxFace face;
if (voxels.findRayIntersection(origin, direction, detail, distance, face)) {
// use the face to determine the side on which to create a neighbor
switch (face) {
case MIN_X_FACE:
detail.x -= detail.s;
break;
case MAX_X_FACE:
detail.x += detail.s;
break;
case MIN_Y_FACE:
detail.y -= detail.s;
break;
case MAX_Y_FACE:
detail.y += detail.s;
break;
case MIN_Z_FACE:
detail.z -= detail.s;
break;
case MAX_Z_FACE:
detail.z += detail.s;
break;
}
unsigned char* bufferOut;
int sizeOut;
if (createVoxelEditMessage(PACKET_HEADER_SET_VOXEL, 0, 1, &detail, bufferOut, sizeOut)){
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1);
delete bufferOut;
glm::vec3 position = (myAvatar.getPosition() + myAvatar.getCameraDirection()) * (1.0f / TREE_SCALE);
detail.s = ::mouseVoxelScale;
detail.x = detail.s * floor(position.x / detail.s);
detail.y = detail.s * floor(position.y / detail.s);
detail.z = detail.s * floor(position.z / detail.s);
detail.red = 128;
detail.green = 128;
detail.blue = 128;
sendVoxelEditMessage(PACKET_HEADER_SET_VOXEL, detail);
// create the voxel locally so it appears immediately
voxels.createVoxel(detail.x, detail.y, detail.z, detail.s, detail.red, detail.green, detail.blue);
}
// create the voxel locally so it appears immediately
voxels.createVoxel(detail.x, detail.y, detail.z, detail.s, detail.red, detail.green, detail.blue);
}
void addVoxelUnderCursor() {
if (::mouseVoxel.s != 0) {
sendVoxelEditMessage(PACKET_HEADER_SET_VOXEL, ::mouseVoxel);
// create the voxel locally so it appears immediately
voxels.createVoxel(::mouseVoxel.x, ::mouseVoxel.y, ::mouseVoxel.z, ::mouseVoxel.s,
::mouseVoxel.red, ::mouseVoxel.green, ::mouseVoxel.blue);
}
}
void deleteVoxelUnderCursor() {
glm::vec3 origin, direction;
viewFrustum.computePickRay(mouseX / (float)WIDTH, mouseY / (float)HEIGHT, origin, direction);
VoxelDetail detail;
float distance;
BoxFace face;
if (voxels.findRayIntersection(origin, direction, detail, distance, face)) {
unsigned char* bufferOut;
int sizeOut;
if (createVoxelEditMessage(PACKET_HEADER_ERASE_VOXEL, 0, 1, &detail, bufferOut, sizeOut)){
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1);
delete bufferOut;
// delete the voxel locally so it disappears immediately
voxels.deleteVoxelAt(detail.x, detail.y, detail.z, detail.s);
}
if (::mouseVoxel.s != 0) {
sendVoxelEditMessage(PACKET_HEADER_ERASE_VOXEL, ::mouseVoxel);
// delete the voxel locally so it disappears immediately
voxels.deleteVoxelAt(::mouseVoxel.x, ::mouseVoxel.y, ::mouseVoxel.z, ::mouseVoxel.s);
}
}
@ -1627,8 +1603,12 @@ void key(unsigned char k, int x, int y) {
if (k == '^') ::shiftPaintingColor(); // shifts randomize color between R,G,B dominant
if (k == '-') ::sendVoxelServerEraseAll(); // sends erase all command to voxel server
if (k == '%') ::sendVoxelServerAddScene(); // sends add scene command to voxel server
if (k == '1') ::addVoxelUnderCursor();
if (k == '2') ::deleteVoxelUnderCursor();
if (k == '1') ::mouseMode = ADD_VOXEL_MODE;
if (k == '2') ::mouseMode = DELETE_VOXEL_MODE;
if (k == '3') ::mouseMode = COLOR_VOXEL_MODE;
if (k == '4') addVoxelInFrontOfAvatar();
if (k == '5') ::mouseVoxelScale /= 2;
if (k == '6') ::mouseVoxelScale *= 2;
if (k == 'n' || k == 'N')
{
noiseOn = !noiseOn; // Toggle noise
@ -1722,6 +1702,28 @@ void* networkReceive(void* args) {
return NULL;
}
glm::vec3 getFaceVector(BoxFace face) {
switch (face) {
case MIN_X_FACE:
return glm::vec3(-1, 0, 0);
case MAX_X_FACE:
return glm::vec3(1, 0, 0);
case MIN_Y_FACE:
return glm::vec3(0, -1, 0);
case MAX_Y_FACE:
return glm::vec3(0, 1, 0);
case MIN_Z_FACE:
return glm::vec3(0, 0, -1);
case MAX_Z_FACE:
return glm::vec3(0, 0, 1);
}
}
void idle(void) {
timeval check;
gettimeofday(&check, NULL);
@ -1739,7 +1741,50 @@ void idle(void) {
// tell my avatar if the mouse is being pressed...
myAvatar.setMousePressed(mousePressed);
// check what's under the mouse and update the mouse voxel
glm::vec3 origin, direction;
viewFrustum.computePickRay(mouseX / (float)WIDTH, mouseY / (float)HEIGHT, origin, direction);
float distance;
BoxFace face;
::mouseVoxel.s = 0.0f;
if (voxels.findRayIntersection(origin, direction, ::mouseVoxel, distance, face)) {
// find the nearest voxel with the desired scale
if (::mouseVoxelScale > ::mouseVoxel.s) {
::mouseVoxel.x = ::mouseVoxelScale * floorf(::mouseVoxel.x / ::mouseVoxelScale);
::mouseVoxel.y = ::mouseVoxelScale * floorf(::mouseVoxel.y / ::mouseVoxelScale);
::mouseVoxel.z = ::mouseVoxelScale * floorf(::mouseVoxel.z / ::mouseVoxelScale);
::mouseVoxel.s = ::mouseVoxelScale;
} else if (::mouseVoxelScale < ::mouseVoxel.s) {
glm::vec3 pt = (origin + direction * distance) / (float)TREE_SCALE -
getFaceVector(face) * (::mouseVoxelScale * 0.5f);
::mouseVoxel.x = ::mouseVoxelScale * floorf(pt.x / ::mouseVoxelScale);
::mouseVoxel.y = ::mouseVoxelScale * floorf(pt.y / ::mouseVoxelScale);
::mouseVoxel.z = ::mouseVoxelScale * floorf(pt.z / ::mouseVoxelScale);
::mouseVoxel.s = ::mouseVoxelScale;
}
if (::mouseMode == ADD_VOXEL_MODE) {
// use the face to determine the side on which to create a neighbor
glm::vec3 offset = getFaceVector(face);
::mouseVoxel.x += offset.x * ::mouseVoxel.s;
::mouseVoxel.y += offset.y * ::mouseVoxel.s;
::mouseVoxel.z += offset.z * ::mouseVoxel.s;
} else if (::mouseMode == COLOR_VOXEL_MODE) {
::mouseVoxel.red = 0;
::mouseVoxel.green = 255;
::mouseVoxel.blue = 0;
} else { // ::mouseMode == DELETE_VOXEL_MODE
// red indicates deletion
::mouseVoxel.red = 255;
::mouseVoxel.green = ::mouseVoxel.blue = 0;
}
}
// walking triggers the handControl to stop
if (myAvatar.getMode() == AVATAR_MODE_WALKING) {
handControl.stop();
@ -1853,22 +1898,54 @@ glm::vec3 getGravity(glm::vec3 pos) {
}
}
bool menuDisplayed = false;
void mouseFunc(int button, int state, int x, int y) {
bool menuFound = menu.mouseClick(x, y);
//catch mouse actions on the menu
bool menuClickedOrUnclicked = menu.mouseClick(x, y);
// If we didn't previously have the menu displayed, and we did just click on the menu, then
// go into menuDisplayed mode....
if (!::menuDisplayed && menuFound) {
::menuDisplayed = true;
}
if (!menuClickedOrUnclicked) {
if ( button == GLUT_LEFT_BUTTON ) {
mouseX = x;
mouseY = y;
if (state == GLUT_DOWN ) {
// If the menu was displayed, and we're not over a menu, then leave menu mode
if (::menuDisplayed && !menuFound) {
::menuDisplayed = false;
menu.hidePopupMenu();
}
// In menu displayed mode use old logic
if (::menuDisplayed) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
if (state == GLUT_DOWN && !menu.mouseClick(x, y)) {
mouseX = x;
mouseY = y;
mousePressed = 1;
} else if (state == GLUT_UP ) {
} else if (state == GLUT_UP) {
mouseX = x;
mouseY = y;
mousePressed = 0;
}
}
} else {
if (button == GLUT_LEFT_BUTTON) {
mouseX = x;
mouseY = y;
if (state == GLUT_DOWN) {
mousePressed = 1;
if (::mouseMode == ADD_VOXEL_MODE || ::mouseMode == COLOR_VOXEL_MODE) {
addVoxelUnderCursor();
} else { // ::mouseMode == DELETE_VOXEL_MODE
deleteVoxelUnderCursor();
}
} else if (state == GLUT_UP) {
mousePressed = 0;
}
} else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
deleteVoxelUnderCursor();
}
}
}
@ -1964,9 +2041,9 @@ int main(int argc, const char * argv[]) {
#endif
// we need to create a QApplication instance in order to use Qt's font rendering
app = new QApplication(argc, const_cast<char**>(argv));
Application app(argc, const_cast<char**>(argv));
printLog( "Created QT Application.\n" );
// Before we render anything, let's set up our viewFrustumOffsetCamera with a sufficiently large
// field of view and near and far clip to make it interesting.
//viewFrustumOffsetCamera.setFieldOfView(90.0);

View file

@ -24,6 +24,7 @@ public:
void render(int screenwidth, int screenheight);
void renderColumn(int i);
MenuColumn* addColumn(const char *columnName);
void hidePopupMenu() { currentColumn = -1; };
private:
std::vector<MenuColumn> columns;
int currentColumn;

View file

@ -44,6 +44,7 @@ void VoxelNode::init(unsigned char * octalCode) {
_glBufferIndex = GLBUFFER_INDEX_UNKNOWN;
_isDirty = true;
_shouldRender = false;
_isStagedForDeletion = false;
calculateAABox();
}

View file

@ -27,6 +27,7 @@ private:
glBufferIndex _glBufferIndex;
bool _isDirty;
bool _shouldRender;
bool _isStagedForDeletion;
AABox _box;
unsigned char* _octalCode;
VoxelNode* _children[8];
@ -66,9 +67,15 @@ public:
glBufferIndex getBufferIndex() const { return _glBufferIndex; };
bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); };
void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; };
// Used by VoxelSystem for rendering in/out of view and LOD
void setShouldRender(bool shouldRender);
bool getShouldRender() const { return _shouldRender; }
// Used by VoxelSystem to mark a node as to be deleted on next render pass
void stageForDeletion() { _isStagedForDeletion = true; };
bool isStagedForDeletion() const { return _isStagedForDeletion; }
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
void setFalseColor(colorPart red, colorPart green, colorPart blue);
void setFalseColored(bool isFalseColored);

View file

@ -620,7 +620,8 @@ bool findRayOperation(VoxelNode* node, void* extraData) {
if (!node->isLeaf()) {
return true; // recurse on children
}
if (!args->found || distance < args->distance) {
distance *= TREE_SCALE;
if (node->isColored() && (!args->found || distance < args->distance)) {
args->node = node;
args->distance = distance;
args->face = face;