mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 06:18:52 +02:00
resolve conflicts on merge with upstream/master
This commit is contained in:
commit
ef1ff01188
32 changed files with 1387 additions and 412 deletions
|
@ -84,7 +84,7 @@ and features are available via menus in the Interface application.
|
||||||
Other components
|
Other components
|
||||||
========
|
========
|
||||||
|
|
||||||
voxel-server, animation-server, audio-mixer, avatar-mixer, domain-server,
|
assignment-client, animation-server, domain-server,
|
||||||
pairing-server and space-server are architectural components that will allow
|
pairing-server and space-server are architectural components that will allow
|
||||||
you to run the full stack of the virtual world should you choose to.
|
you to run the full stack of the virtual world should you choose to.
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
#include "Agent.h"
|
#include "Agent.h"
|
||||||
#include "voxels/VoxelScriptingInterface.h"
|
#include "voxels/VoxelScriptingInterface.h"
|
||||||
|
|
||||||
Agent::Agent(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) {
|
Agent::Agent(const unsigned char* dataBuffer, int numBytes) :
|
||||||
|
Assignment(dataBuffer, numBytes),
|
||||||
|
_shouldStop(false)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
interface/resources/shaders/passthrough.vert
Normal file
10
interface/resources/shaders/passthrough.vert
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
attribute float voxelSizeIn;
|
||||||
|
varying float voxelSize;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
gl_FrontColor = gl_Color;
|
||||||
|
gl_Position = gl_Vertex; // don't call ftransform(), because we do projection in geometry shader
|
||||||
|
voxelSize = voxelSizeIn;
|
||||||
|
}
|
77
interface/resources/shaders/voxel.geom
Normal file
77
interface/resources/shaders/voxel.geom
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#version 120
|
||||||
|
#extension GL_ARB_geometry_shader4 : enable
|
||||||
|
|
||||||
|
//
|
||||||
|
// VOXEL GEOMETRY SHADER
|
||||||
|
//
|
||||||
|
// Input: gl_VerticesIn/gl_PositionIn
|
||||||
|
// GL_POINTS
|
||||||
|
// Assumes vertex shader has not transformed coordinates
|
||||||
|
// Each gl_PositionIn is the corner of voxel
|
||||||
|
// varying voxelSize - which is the voxel size
|
||||||
|
//
|
||||||
|
// Note: In vertex shader doesn't do any transform. Therefore passing the 3D world coordinates xyz to us
|
||||||
|
//
|
||||||
|
// Output: GL_TRIANGLE_STRIP
|
||||||
|
//
|
||||||
|
// Issues:
|
||||||
|
// how do we need to handle lighting of these colors??
|
||||||
|
// how do we handle normals?
|
||||||
|
// check for size=0 and don't output the primitive
|
||||||
|
//
|
||||||
|
|
||||||
|
varying in float voxelSize[1];
|
||||||
|
|
||||||
|
const int VERTICES_PER_FACE = 4;
|
||||||
|
const int COORD_PER_VERTEX = 3;
|
||||||
|
const int COORD_PER_FACE = COORD_PER_VERTEX * VERTICES_PER_FACE;
|
||||||
|
|
||||||
|
void faceOfVoxel(vec4 corner, float scale, float[COORD_PER_FACE] facePoints, vec4 color, vec4 normal) {
|
||||||
|
for (int v = 0; v < VERTICES_PER_FACE; v++ ) {
|
||||||
|
vec4 vertex = corner;
|
||||||
|
for (int c = 0; c < COORD_PER_VERTEX; c++ ) {
|
||||||
|
int cIndex = c + (v * COORD_PER_VERTEX);
|
||||||
|
vertex[c] += (facePoints[cIndex] * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FrontColor = color * (gl_LightModel.ambient + gl_LightSource[0].ambient +
|
||||||
|
gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position)));
|
||||||
|
|
||||||
|
gl_Position = gl_ModelViewProjectionMatrix * vertex;
|
||||||
|
EmitVertex();
|
||||||
|
}
|
||||||
|
EndPrimitive();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
//increment variable
|
||||||
|
int i;
|
||||||
|
vec4 corner;
|
||||||
|
float scale;
|
||||||
|
|
||||||
|
float bottomFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1 );
|
||||||
|
float topFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1 );
|
||||||
|
float rightFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1 );
|
||||||
|
float leftFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1 );
|
||||||
|
float frontFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 );
|
||||||
|
float backFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1 );
|
||||||
|
|
||||||
|
vec4 bottomNormal = vec4(0.0, -1, 0.0, 0.0);
|
||||||
|
vec4 topNormal = vec4(0.0, 1, 0.0, 0.0);
|
||||||
|
vec4 rightNormal = vec4( -1, 0.0, 0.0, 0.0);
|
||||||
|
vec4 leftNormal = vec4( 1, 0.0, 0.0, 0.0);
|
||||||
|
vec4 frontNormal = vec4(0.0, 0.0, -1, 0.0);
|
||||||
|
vec4 backNormal = vec4(0.0, 0.0, 1, 0.0);
|
||||||
|
|
||||||
|
for(i = 0; i < gl_VerticesIn; i++) {
|
||||||
|
corner = gl_PositionIn[i];
|
||||||
|
scale = voxelSize[i];
|
||||||
|
faceOfVoxel(corner, scale, bottomFace, gl_FrontColorIn[i], bottomNormal);
|
||||||
|
faceOfVoxel(corner, scale, topFace, gl_FrontColorIn[i], topNormal );
|
||||||
|
faceOfVoxel(corner, scale, rightFace, gl_FrontColorIn[i], rightNormal );
|
||||||
|
faceOfVoxel(corner, scale, leftFace, gl_FrontColorIn[i], leftNormal );
|
||||||
|
faceOfVoxel(corner, scale, frontFace, gl_FrontColorIn[i], frontNormal );
|
||||||
|
faceOfVoxel(corner, scale, backFace, gl_FrontColorIn[i], backNormal );
|
||||||
|
}
|
||||||
|
}
|
|
@ -116,7 +116,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_nudgeStarted(false),
|
_nudgeStarted(false),
|
||||||
_lookingAlongX(false),
|
_lookingAlongX(false),
|
||||||
_lookingAwayFromOrigin(true),
|
_lookingAwayFromOrigin(true),
|
||||||
_isLookingAtOtherAvatar(false),
|
_lookatTargetAvatar(NULL),
|
||||||
_lookatIndicatorScale(1.0f),
|
_lookatIndicatorScale(1.0f),
|
||||||
_perfStatsOn(false),
|
_perfStatsOn(false),
|
||||||
_chatEntryOn(false),
|
_chatEntryOn(false),
|
||||||
|
@ -151,6 +151,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
|
|
||||||
NodeList::getInstance()->addHook(&_voxels);
|
NodeList::getInstance()->addHook(&_voxels);
|
||||||
NodeList::getInstance()->addHook(this);
|
NodeList::getInstance()->addHook(this);
|
||||||
|
NodeList::getInstance()->addDomainListener(this);
|
||||||
|
|
||||||
|
|
||||||
// network receive thread and voxel parsing thread are both controlled by the --nonblocking command line
|
// network receive thread and voxel parsing thread are both controlled by the --nonblocking command line
|
||||||
|
@ -231,6 +232,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
Application::~Application() {
|
Application::~Application() {
|
||||||
NodeList::getInstance()->removeHook(&_voxels);
|
NodeList::getInstance()->removeHook(&_voxels);
|
||||||
NodeList::getInstance()->removeHook(this);
|
NodeList::getInstance()->removeHook(this);
|
||||||
|
NodeList::getInstance()->removeDomainListener(this);
|
||||||
|
|
||||||
_sharedVoxelSystem.changeTree(new VoxelTree);
|
_sharedVoxelSystem.changeTree(new VoxelTree);
|
||||||
|
|
||||||
|
@ -309,8 +311,6 @@ void Application::initializeGL() {
|
||||||
char title[50];
|
char title[50];
|
||||||
sprintf(title, "Interface: %4.2f seconds\n", startupTime);
|
sprintf(title, "Interface: %4.2f seconds\n", startupTime);
|
||||||
qDebug("%s", title);
|
qDebug("%s", title);
|
||||||
_window->setWindowTitle(title);
|
|
||||||
|
|
||||||
const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
|
const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
|
||||||
|
|
||||||
// ask the Logstash class to record the startup time
|
// ask the Logstash class to record the startup time
|
||||||
|
@ -389,6 +389,7 @@ void Application::paintGL() {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_glowEffect.prepare();
|
_glowEffect.prepare();
|
||||||
|
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
@ -541,6 +542,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
_myAvatar.setDriveKeys(UP, 1);
|
_myAvatar.setDriveKeys(UP, 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Qt::Key_Asterisk:
|
||||||
|
Menu::getInstance()->triggerOption(MenuOption::Stars);
|
||||||
|
break;
|
||||||
|
|
||||||
case Qt::Key_C:
|
case Qt::Key_C:
|
||||||
if (isShifted) {
|
if (isShifted) {
|
||||||
|
@ -810,8 +815,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
case Qt::Key_F:
|
case Qt::Key_F:
|
||||||
if (isShifted) {
|
if (isShifted) {
|
||||||
Menu::getInstance()->triggerOption(MenuOption::DisplayFrustum);
|
Menu::getInstance()->triggerOption(MenuOption::DisplayFrustum);
|
||||||
} else {
|
|
||||||
Menu::getInstance()->triggerOption(MenuOption::Fullscreen);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Qt::Key_V:
|
case Qt::Key_V:
|
||||||
|
@ -974,7 +977,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
|
|
||||||
maybeEditVoxelUnderCursor();
|
maybeEditVoxelUnderCursor();
|
||||||
|
|
||||||
if (!_palette.isActive() && (!_isHoverVoxel || _isLookingAtOtherAvatar)) {
|
if (!_palette.isActive() && (!_isHoverVoxel || _lookatTargetAvatar)) {
|
||||||
_pieMenu.mousePressEvent(_mouseX, _mouseY);
|
_pieMenu.mousePressEvent(_mouseX, _mouseY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -998,6 +1001,17 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
|
|
||||||
_audio.startCollisionSound(1.0, frequency, 0.0, HOVER_VOXEL_DECAY);
|
_audio.startCollisionSound(1.0, frequency, 0.0, HOVER_VOXEL_DECAY);
|
||||||
_isHoverVoxelSounding = true;
|
_isHoverVoxelSounding = true;
|
||||||
|
|
||||||
|
const float PERCENTAGE_TO_MOVE_TOWARD = 0.90f;
|
||||||
|
glm::vec3 newTarget = getMouseVoxelWorldCoordinates(_hoverVoxel);
|
||||||
|
glm::vec3 myPosition = _myAvatar.getPosition();
|
||||||
|
|
||||||
|
// If there is not an action tool set (add, delete, color), move to this voxel
|
||||||
|
if (!(Menu::getInstance()->isOptionChecked(MenuOption::VoxelAddMode) ||
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::VoxelDeleteMode) ||
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::VoxelColorMode))) {
|
||||||
|
_myAvatar.setMoveTarget(myPosition + (newTarget - myPosition) * PERCENTAGE_TO_MOVE_TOWARD);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (event->button() == Qt::RightButton && Menu::getInstance()->isVoxelModeActionChecked()) {
|
} else if (event->button() == Qt::RightButton && Menu::getInstance()->isVoxelModeActionChecked()) {
|
||||||
|
@ -1503,7 +1517,7 @@ void Application::setListenModeSingleSource() {
|
||||||
glm::vec3 eyePositionIgnored;
|
glm::vec3 eyePositionIgnored;
|
||||||
uint16_t nodeID;
|
uint16_t nodeID;
|
||||||
|
|
||||||
if (isLookingAtOtherAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeID)) {
|
if (findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeID)) {
|
||||||
_audio.addListenSource(nodeID);
|
_audio.addListenSource(nodeID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1518,7 +1532,6 @@ void Application::initDisplay() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::init() {
|
void Application::init() {
|
||||||
_voxels.init();
|
|
||||||
_sharedVoxelSystemViewFrustum.setPosition(glm::vec3(TREE_SCALE / 2.0f,
|
_sharedVoxelSystemViewFrustum.setPosition(glm::vec3(TREE_SCALE / 2.0f,
|
||||||
TREE_SCALE / 2.0f,
|
TREE_SCALE / 2.0f,
|
||||||
3.0f * TREE_SCALE / 2.0f));
|
3.0f * TREE_SCALE / 2.0f));
|
||||||
|
@ -1539,6 +1552,7 @@ void Application::init() {
|
||||||
|
|
||||||
_glowEffect.init();
|
_glowEffect.init();
|
||||||
_ambientOcclusionEffect.init();
|
_ambientOcclusionEffect.init();
|
||||||
|
_voxelShader.init();
|
||||||
|
|
||||||
_handControl.setScreenDimensions(_glWidget->width(), _glWidget->height());
|
_handControl.setScreenDimensions(_glWidget->width(), _glWidget->height());
|
||||||
|
|
||||||
|
@ -1569,9 +1583,15 @@ void Application::init() {
|
||||||
if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) {
|
if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) {
|
||||||
_audio.setJitterBufferSamples(Menu::getInstance()->getAudioJitterBufferSamples());
|
_audio.setJitterBufferSamples(Menu::getInstance()->getAudioJitterBufferSamples());
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug("Loaded settings.\n");
|
qDebug("Loaded settings.\n");
|
||||||
|
|
||||||
|
// Set up VoxelSystem after loading preferences so we can get the desired max voxel count
|
||||||
|
_voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels());
|
||||||
|
_voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader));
|
||||||
|
_voxels.setUseByteNormals(Menu::getInstance()->isOptionChecked(MenuOption::UseByteNormals));
|
||||||
|
_voxels.init();
|
||||||
|
|
||||||
|
|
||||||
Avatar::sendAvatarURLsMessage(_myAvatar.getVoxels()->getVoxelURL(), _myAvatar.getHead().getBlendFace().getModelURL());
|
Avatar::sendAvatarURLsMessage(_myAvatar.getVoxels()->getVoxelURL(), _myAvatar.getHead().getBlendFace().getModelURL());
|
||||||
|
|
||||||
_palette.init(_glWidget->width(), _glWidget->height());
|
_palette.init(_glWidget->width(), _glWidget->height());
|
||||||
|
@ -1596,12 +1616,16 @@ const float MAX_AVATAR_EDIT_VELOCITY = 1.0f;
|
||||||
const float MAX_VOXEL_EDIT_DISTANCE = 20.0f;
|
const float MAX_VOXEL_EDIT_DISTANCE = 20.0f;
|
||||||
const float HEAD_SPHERE_RADIUS = 0.07;
|
const float HEAD_SPHERE_RADIUS = 0.07;
|
||||||
|
|
||||||
|
|
||||||
static uint16_t DEFAULT_NODE_ID_REF = 1;
|
static uint16_t DEFAULT_NODE_ID_REF = 1;
|
||||||
|
|
||||||
|
void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
Avatar* Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
glm::vec3& eyePosition) {
|
||||||
glm::vec3& eyePosition, uint16_t& nodeID = DEFAULT_NODE_ID_REF) {
|
|
||||||
|
_lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF);
|
||||||
|
}
|
||||||
|
|
||||||
|
Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
|
glm::vec3& eyePosition, uint16_t& nodeID = DEFAULT_NODE_ID_REF) {
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
|
@ -1739,6 +1763,11 @@ void Application::update(float deltaTime) {
|
||||||
|
|
||||||
// Update faceshift
|
// Update faceshift
|
||||||
_faceshift.update();
|
_faceshift.update();
|
||||||
|
|
||||||
|
// Copy angular velocity if measured by faceshift, to the head
|
||||||
|
if (_faceshift.isActive()) {
|
||||||
|
_myAvatar.getHead().setAngularVelocity(_faceshift.getHeadAngularVelocity());
|
||||||
|
}
|
||||||
|
|
||||||
// if we have faceshift, use that to compute the lookat direction
|
// if we have faceshift, use that to compute the lookat direction
|
||||||
glm::vec3 lookAtRayOrigin = mouseRayOrigin, lookAtRayDirection = mouseRayDirection;
|
glm::vec3 lookAtRayOrigin = mouseRayOrigin, lookAtRayDirection = mouseRayDirection;
|
||||||
|
@ -1748,8 +1777,8 @@ void Application::update(float deltaTime) {
|
||||||
_faceshift.getEstimatedEyePitch(), _faceshift.getEstimatedEyeYaw(), 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f);
|
_faceshift.getEstimatedEyePitch(), _faceshift.getEstimatedEyeYaw(), 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLookingAtOtherAvatar = isLookingAtOtherAvatar(lookAtRayOrigin, lookAtRayDirection, lookAtSpot);
|
updateLookatTargetAvatar(lookAtRayOrigin, lookAtRayDirection, lookAtSpot);
|
||||||
if (_isLookingAtOtherAvatar) {
|
if (_lookatTargetAvatar) {
|
||||||
// If the mouse is over another avatar's head...
|
// If the mouse is over another avatar's head...
|
||||||
_myAvatar.getHead().setLookAtPosition(lookAtSpot);
|
_myAvatar.getHead().setLookAtPosition(lookAtSpot);
|
||||||
} else if (_isHoverVoxel && !_faceshift.isActive()) {
|
} else if (_isHoverVoxel && !_faceshift.isActive()) {
|
||||||
|
@ -1921,7 +1950,7 @@ void Application::update(float deltaTime) {
|
||||||
if (!avatar->isInitialized()) {
|
if (!avatar->isInitialized()) {
|
||||||
avatar->init();
|
avatar->init();
|
||||||
}
|
}
|
||||||
avatar->simulate(deltaTime, NULL, 0.f);
|
avatar->simulate(deltaTime, NULL);
|
||||||
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
|
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
|
||||||
}
|
}
|
||||||
node->unlock();
|
node->unlock();
|
||||||
|
@ -1936,9 +1965,9 @@ void Application::update(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TransmitterDrive) && _myTransmitter.isConnected()) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::TransmitterDrive) && _myTransmitter.isConnected()) {
|
||||||
_myAvatar.simulate(deltaTime, &_myTransmitter, Menu::getInstance()->getGyroCameraSensitivity());
|
_myAvatar.simulate(deltaTime, &_myTransmitter);
|
||||||
} else {
|
} else {
|
||||||
_myAvatar.simulate(deltaTime, NULL, Menu::getInstance()->getGyroCameraSensitivity());
|
_myAvatar.simulate(deltaTime, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// no transmitter drive implies transmitter pick
|
// no transmitter drive implies transmitter pick
|
||||||
|
@ -2063,15 +2092,15 @@ void Application::updateAvatar(float deltaTime) {
|
||||||
const float MIDPOINT_OF_SCREEN = 0.5;
|
const float MIDPOINT_OF_SCREEN = 0.5;
|
||||||
|
|
||||||
// Only use gyro to set lookAt if mouse hasn't selected an avatar
|
// Only use gyro to set lookAt if mouse hasn't selected an avatar
|
||||||
if (!_isLookingAtOtherAvatar) {
|
if (!_lookatTargetAvatar) {
|
||||||
|
|
||||||
// Set lookAtPosition if an avatar is at the center of the screen
|
// Set lookAtPosition if an avatar is at the center of the screen
|
||||||
glm::vec3 screenCenterRayOrigin, screenCenterRayDirection;
|
glm::vec3 screenCenterRayOrigin, screenCenterRayDirection;
|
||||||
_viewFrustum.computePickRay(MIDPOINT_OF_SCREEN, MIDPOINT_OF_SCREEN, screenCenterRayOrigin, screenCenterRayDirection);
|
_viewFrustum.computePickRay(MIDPOINT_OF_SCREEN, MIDPOINT_OF_SCREEN, screenCenterRayOrigin, screenCenterRayDirection);
|
||||||
|
|
||||||
glm::vec3 eyePosition;
|
glm::vec3 eyePosition;
|
||||||
_isLookingAtOtherAvatar = isLookingAtOtherAvatar(screenCenterRayOrigin, screenCenterRayDirection, eyePosition);
|
updateLookatTargetAvatar(screenCenterRayOrigin, screenCenterRayDirection, eyePosition);
|
||||||
if (_isLookingAtOtherAvatar) {
|
if (_lookatTargetAvatar) {
|
||||||
glm::vec3 myLookAtFromMouse(eyePosition);
|
glm::vec3 myLookAtFromMouse(eyePosition);
|
||||||
_myAvatar.getHead().setLookAtPosition(myLookAtFromMouse);
|
_myAvatar.getHead().setLookAtPosition(myLookAtFromMouse);
|
||||||
}
|
}
|
||||||
|
@ -2540,7 +2569,7 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls));
|
Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls));
|
||||||
_myAvatar.setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
|
_myAvatar.setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::LookAtIndicator) && _isLookingAtOtherAvatar) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::LookAtIndicator) && _lookatTargetAvatar) {
|
||||||
renderLookatIndicator(_lookatOtherPosition, whichCamera);
|
renderLookatIndicator(_lookatOtherPosition, whichCamera);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2561,7 +2590,7 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) {
|
||||||
renderViewFrustum(_viewFrustum);
|
renderViewFrustum(_viewFrustum);
|
||||||
}
|
}
|
||||||
|
|
||||||
// render voxel fades if they exist
|
// render voxel fades if they exist
|
||||||
if (_voxelFades.size() > 0) {
|
if (_voxelFades.size() > 0) {
|
||||||
for(std::vector<VoxelFade>::iterator fade = _voxelFades.begin(); fade != _voxelFades.end();) {
|
for(std::vector<VoxelFade>::iterator fade = _voxelFades.begin(); fade != _voxelFades.end();) {
|
||||||
|
@ -2806,28 +2835,39 @@ void Application::displayStats() {
|
||||||
|
|
||||||
std::stringstream voxelStats;
|
std::stringstream voxelStats;
|
||||||
voxelStats.precision(4);
|
voxelStats.precision(4);
|
||||||
voxelStats << "Voxels Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K Updated: " << _voxels.getVoxelsUpdated()/1000.f << "K";
|
voxelStats << "Voxels Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K " <<
|
||||||
|
"Updated: " << _voxels.getVoxelsUpdated()/1000.f << "K " <<
|
||||||
|
"Max: " << _voxels.getMaxVoxels()/1000.f << "K ";
|
||||||
drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||||
|
|
||||||
|
voxelStats.str("");
|
||||||
|
voxelStats << "Voxels Memory RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB " <<
|
||||||
|
"VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB ";
|
||||||
|
if (_voxels.hasVoxelMemoryUsageGPU()) {
|
||||||
|
voxelStats << "GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB ";
|
||||||
|
}
|
||||||
|
|
||||||
|
drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||||
|
|
||||||
voxelStats.str("");
|
voxelStats.str("");
|
||||||
char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS);
|
char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS);
|
||||||
voxelStats << "Voxels Sent from Server: " << voxelDetails;
|
voxelStats << "Voxels Sent from Server: " << voxelDetails;
|
||||||
drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||||
|
|
||||||
voxelStats.str("");
|
voxelStats.str("");
|
||||||
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ELAPSED);
|
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ELAPSED);
|
||||||
voxelStats << "Scene Send Time from Server: " << voxelDetails;
|
voxelStats << "Scene Send Time from Server: " << voxelDetails;
|
||||||
drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
drawtext(10, statsVerticalOffset + 290, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||||
|
|
||||||
voxelStats.str("");
|
voxelStats.str("");
|
||||||
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ENCODE);
|
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ENCODE);
|
||||||
voxelStats << "Encode Time on Server: " << voxelDetails;
|
voxelStats << "Encode Time on Server: " << voxelDetails;
|
||||||
drawtext(10, statsVerticalOffset + 290, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||||
|
|
||||||
voxelStats.str("");
|
voxelStats.str("");
|
||||||
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_MODE);
|
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_MODE);
|
||||||
voxelStats << "Sending Mode: " << voxelDetails;
|
voxelStats << "Sending Mode: " << voxelDetails;
|
||||||
drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||||
|
|
||||||
Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
||||||
char avatarMixerStats[200];
|
char avatarMixerStats[200];
|
||||||
|
@ -2840,7 +2880,7 @@ void Application::displayStats() {
|
||||||
sprintf(avatarMixerStats, "No Avatar Mixer");
|
sprintf(avatarMixerStats, "No Avatar Mixer");
|
||||||
}
|
}
|
||||||
|
|
||||||
drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, avatarMixerStats);
|
drawtext(10, statsVerticalOffset + 350, 0.10f, 0, 1.0, 0, avatarMixerStats);
|
||||||
drawtext(10, statsVerticalOffset + 450, 0.10f, 0, 1.0, 0, (char *)LeapManager::statusString().c_str());
|
drawtext(10, statsVerticalOffset + 450, 0.10f, 0, 1.0, 0, (char *)LeapManager::statusString().c_str());
|
||||||
|
|
||||||
if (_perfStatsOn) {
|
if (_perfStatsOn) {
|
||||||
|
@ -3342,10 +3382,7 @@ void Application::toggleFollowMode() {
|
||||||
mouseRayOrigin, mouseRayDirection);
|
mouseRayOrigin, mouseRayDirection);
|
||||||
glm::vec3 eyePositionIgnored;
|
glm::vec3 eyePositionIgnored;
|
||||||
uint16_t nodeIDIgnored;
|
uint16_t nodeIDIgnored;
|
||||||
Avatar* leadingAvatar = isLookingAtOtherAvatar(mouseRayOrigin,
|
Avatar* leadingAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeIDIgnored);
|
||||||
mouseRayDirection,
|
|
||||||
eyePositionIgnored,
|
|
||||||
nodeIDIgnored);
|
|
||||||
|
|
||||||
_myAvatar.follow(leadingAvatar);
|
_myAvatar.follow(leadingAvatar);
|
||||||
}
|
}
|
||||||
|
@ -3396,6 +3433,11 @@ void Application::attachNewHeadToNode(Node* newNode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::domainChanged(QString domain) {
|
||||||
|
qDebug("Application title set to: %s.\n", domain.toStdString().c_str());
|
||||||
|
_window->setWindowTitle(domain);
|
||||||
|
}
|
||||||
|
|
||||||
void Application::nodeAdded(Node* node) {
|
void Application::nodeAdded(Node* node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3418,6 +3460,8 @@ void Application::nodeKilled(Node* node) {
|
||||||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||||
_voxelFades.push_back(fade);
|
_voxelFades.push_back(fade);
|
||||||
}
|
}
|
||||||
|
} else if (node->getLinkedData() == _lookatTargetAvatar) {
|
||||||
|
_lookatTargetAvatar = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#include "renderer/AmbientOcclusionEffect.h"
|
#include "renderer/AmbientOcclusionEffect.h"
|
||||||
#include "renderer/GeometryCache.h"
|
#include "renderer/GeometryCache.h"
|
||||||
#include "renderer/GlowEffect.h"
|
#include "renderer/GlowEffect.h"
|
||||||
|
#include "renderer/VoxelShader.h"
|
||||||
#include "renderer/TextureCache.h"
|
#include "renderer/TextureCache.h"
|
||||||
#include "ui/BandwidthDialog.h"
|
#include "ui/BandwidthDialog.h"
|
||||||
#include "ui/ChatEntry.h"
|
#include "ui/ChatEntry.h"
|
||||||
|
@ -76,7 +77,7 @@ static const float NODE_KILLED_RED = 1.0f;
|
||||||
static const float NODE_KILLED_GREEN = 0.0f;
|
static const float NODE_KILLED_GREEN = 0.0f;
|
||||||
static const float NODE_KILLED_BLUE = 0.0f;
|
static const float NODE_KILLED_BLUE = 0.0f;
|
||||||
|
|
||||||
class Application : public QApplication, public NodeListHook, public PacketSenderNotify {
|
class Application : public QApplication, public NodeListHook, public PacketSenderNotify, public DomainChangeListener {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
friend class VoxelPacketProcessor;
|
friend class VoxelPacketProcessor;
|
||||||
|
@ -130,6 +131,8 @@ public:
|
||||||
TextureCache* getTextureCache() { return &_textureCache; }
|
TextureCache* getTextureCache() { return &_textureCache; }
|
||||||
GlowEffect* getGlowEffect() { return &_glowEffect; }
|
GlowEffect* getGlowEffect() { return &_glowEffect; }
|
||||||
|
|
||||||
|
Avatar* getLookatTargetAvatar() const { return _lookatTargetAvatar; }
|
||||||
|
|
||||||
static void controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes,
|
static void controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes,
|
||||||
const char* nodeTypes, int numNodeTypes);
|
const char* nodeTypes, int numNodeTypes);
|
||||||
|
|
||||||
|
@ -142,6 +145,10 @@ public:
|
||||||
virtual void nodeAdded(Node* node);
|
virtual void nodeAdded(Node* node);
|
||||||
virtual void nodeKilled(Node* node);
|
virtual void nodeKilled(Node* node);
|
||||||
virtual void packetSentNotification(ssize_t length);
|
virtual void packetSentNotification(ssize_t length);
|
||||||
|
|
||||||
|
virtual void domainChanged(QString domain);
|
||||||
|
|
||||||
|
VoxelShader& getVoxelShader() { return _voxelShader; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data);
|
void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data);
|
||||||
|
@ -195,8 +202,11 @@ private:
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
Avatar* isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
|
||||||
glm::vec3& eyePosition, uint16_t& nodeID);
|
void updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
|
glm::vec3& eyePosition);
|
||||||
|
Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
|
glm::vec3& eyePosition, uint16_t& nodeID);
|
||||||
bool isLookingAtMyAvatar(Avatar* avatar);
|
bool isLookingAtMyAvatar(Avatar* avatar);
|
||||||
|
|
||||||
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);
|
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);
|
||||||
|
@ -315,7 +325,7 @@ private:
|
||||||
bool _lookingAwayFromOrigin;
|
bool _lookingAwayFromOrigin;
|
||||||
glm::vec3 _nudgeGuidePosition;
|
glm::vec3 _nudgeGuidePosition;
|
||||||
|
|
||||||
bool _isLookingAtOtherAvatar;
|
Avatar* _lookatTargetAvatar;
|
||||||
glm::vec3 _lookatOtherPosition;
|
glm::vec3 _lookatOtherPosition;
|
||||||
float _lookatIndicatorScale;
|
float _lookatIndicatorScale;
|
||||||
|
|
||||||
|
@ -341,6 +351,7 @@ private:
|
||||||
|
|
||||||
GlowEffect _glowEffect;
|
GlowEffect _glowEffect;
|
||||||
AmbientOcclusionEffect _ambientOcclusionEffect;
|
AmbientOcclusionEffect _ambientOcclusionEffect;
|
||||||
|
VoxelShader _voxelShader;
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
Audio _audio;
|
Audio _audio;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QSlider>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
@ -48,7 +49,8 @@ Menu::Menu() :
|
||||||
_frustumDrawMode(FRUSTUM_DRAW_MODE_ALL),
|
_frustumDrawMode(FRUSTUM_DRAW_MODE_ALL),
|
||||||
_viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET),
|
_viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET),
|
||||||
_voxelModeActionsGroup(NULL),
|
_voxelModeActionsGroup(NULL),
|
||||||
_voxelStatsDialog(NULL)
|
_voxelStatsDialog(NULL),
|
||||||
|
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM)
|
||||||
{
|
{
|
||||||
Application *appInstance = Application::getInstance();
|
Application *appInstance = Application::getInstance();
|
||||||
|
|
||||||
|
@ -188,50 +190,36 @@ Menu::Menu() :
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu,
|
addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||||
MenuOption::Fullscreen,
|
MenuOption::Fullscreen,
|
||||||
Qt::Key_F,
|
Qt::CTRL | Qt::META | Qt::Key_F,
|
||||||
false,
|
false,
|
||||||
appInstance,
|
appInstance,
|
||||||
SLOT(setFullscreen(bool)));
|
SLOT(setFullscreen(bool)));
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true);
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::Key_H);
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(viewMenu,
|
QMenu* avatarSizeMenu = viewMenu->addMenu("Avatar Size");
|
||||||
|
|
||||||
|
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||||
MenuOption::IncreaseAvatarSize,
|
MenuOption::IncreaseAvatarSize,
|
||||||
Qt::Key_Plus,
|
Qt::Key_Plus,
|
||||||
appInstance->getAvatar(),
|
appInstance->getAvatar(),
|
||||||
SLOT(increaseSize()));
|
SLOT(increaseSize()));
|
||||||
addActionToQMenuAndActionHash(viewMenu,
|
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||||
MenuOption::DecreaseAvatarSize,
|
MenuOption::DecreaseAvatarSize,
|
||||||
Qt::Key_Minus,
|
Qt::Key_Minus,
|
||||||
appInstance->getAvatar(),
|
appInstance->getAvatar(),
|
||||||
SLOT(decreaseSize()));
|
SLOT(decreaseSize()));
|
||||||
addActionToQMenuAndActionHash(viewMenu,
|
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||||
MenuOption::ResetAvatarSize,
|
MenuOption::ResetAvatarSize,
|
||||||
0,
|
0,
|
||||||
appInstance->getAvatar(),
|
appInstance->getAvatar(),
|
||||||
SLOT(resetSize()));
|
SLOT(resetSize()));
|
||||||
|
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::Key_H);
|
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu,
|
|
||||||
MenuOption::SkeletonTracking,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
appInstance->getWebcam(),
|
|
||||||
SLOT(setSkeletonTrackingOn(bool)));
|
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu,
|
|
||||||
MenuOption::LEDTracking,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
appInstance->getWebcam()->getGrabber(),
|
|
||||||
SLOT(setLEDTrackingOn(bool)));
|
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu,
|
addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||||
MenuOption::OffAxisProjection,
|
MenuOption::OffAxisProjection,
|
||||||
0,
|
0,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
addDisabledActionAndSeparator(viewMenu, "Stats");
|
addDisabledActionAndSeparator(viewMenu, "Stats");
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L);
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L);
|
||||||
|
@ -241,50 +229,126 @@ Menu::Menu() :
|
||||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::VoxelStats, 0, this, SLOT(voxelStatsDetails()));
|
addActionToQMenuAndActionHash(viewMenu, MenuOption::VoxelStats, 0, this, SLOT(voxelStatsDetails()));
|
||||||
|
|
||||||
QMenu* developerMenu = addMenu("Developer");
|
QMenu* developerMenu = addMenu("Developer");
|
||||||
addDisabledActionAndSeparator(developerMenu, "Rendering");
|
|
||||||
|
QMenu* renderOptionsMenu = developerMenu->addMenu("Rendering Options");
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::GroundPlane, 0, true);
|
||||||
|
addActionToQMenuAndActionHash(renderOptionsMenu,
|
||||||
|
MenuOption::GlowMode,
|
||||||
|
0,
|
||||||
|
appInstance->getGlowEffect(),
|
||||||
|
SLOT(cycleRenderMode()));
|
||||||
|
|
||||||
|
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options");
|
||||||
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu,
|
||||||
MenuOption::Voxels,
|
MenuOption::Voxels,
|
||||||
Qt::SHIFT | Qt::Key_V,
|
Qt::SHIFT | Qt::Key_V,
|
||||||
true,
|
true,
|
||||||
appInstance,
|
appInstance,
|
||||||
SLOT(setRenderVoxels(bool)));
|
SLOT(setRenderVoxels(bool)));
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::VoxelTextures);
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::AmbientOcclusion);
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stars, 0, true);
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0,
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true);
|
false, this, SLOT(switchVoxelShader()));
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::GroundPlane, 0, true);
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Avatars, 0, true);
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseByteNormals, 0,
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::AvatarAsBalls);
|
false, Application::getInstance()->getVoxels(), SLOT(setUseByteNormals(bool)));
|
||||||
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseGlobalNormals, 0,
|
||||||
|
false, Application::getInstance()->getVoxels(), SLOT(setUseGlobalNormals(bool)));
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(developerMenu,
|
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");
|
||||||
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::AvatarAsBalls);
|
||||||
|
|
||||||
|
addActionToQMenuAndActionHash(avatarOptionsMenu,
|
||||||
MenuOption::VoxelMode,
|
MenuOption::VoxelMode,
|
||||||
0,
|
0,
|
||||||
appInstance->getAvatar()->getVoxels(),
|
appInstance->getAvatar()->getVoxels(),
|
||||||
SLOT(cycleMode()));
|
SLOT(cycleMode()));
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(developerMenu,
|
addActionToQMenuAndActionHash(avatarOptionsMenu,
|
||||||
MenuOption::FaceMode,
|
MenuOption::FaceMode,
|
||||||
0,
|
0,
|
||||||
&appInstance->getAvatar()->getHead().getFace(),
|
&appInstance->getAvatar()->getHead().getFace(),
|
||||||
SLOT(cycleRenderMode()));
|
SLOT(cycleRenderMode()));
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(developerMenu,
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::UsePerlinFace, 0, false);
|
||||||
MenuOption::GlowMode,
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtIndicator, 0, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu,
|
||||||
|
MenuOption::FaceshiftTCP,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
appInstance->getFaceshift(),
|
||||||
|
SLOT(setTCPEnabled(bool)));
|
||||||
|
|
||||||
|
QMenu* webcamOptionsMenu = developerMenu->addMenu("Webcam Options");
|
||||||
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(webcamOptionsMenu,
|
||||||
|
MenuOption::Webcam,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
appInstance->getWebcam(),
|
||||||
|
SLOT(setEnabled(bool)));
|
||||||
|
|
||||||
|
addActionToQMenuAndActionHash(webcamOptionsMenu,
|
||||||
|
MenuOption::WebcamMode,
|
||||||
0,
|
0,
|
||||||
appInstance->getGlowEffect(),
|
appInstance->getWebcam()->getGrabber(),
|
||||||
SLOT(cycleRenderMode()));
|
SLOT(cycleVideoSendMode()));
|
||||||
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(webcamOptionsMenu,
|
||||||
|
MenuOption::WebcamTexture,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
appInstance->getWebcam()->getGrabber(),
|
||||||
|
SLOT(setDepthOnly(bool)));
|
||||||
|
|
||||||
|
QMenu* raveGloveOptionsMenu = developerMenu->addMenu("Rave Glove Options");
|
||||||
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(raveGloveOptionsMenu, MenuOption::SimulateLeapHand);
|
||||||
|
addCheckableActionToQMenuAndActionHash(raveGloveOptionsMenu, MenuOption::TestRaveGlove);
|
||||||
|
|
||||||
|
|
||||||
|
QMenu* gyroOptionsMenu = developerMenu->addMenu("Gyro Options");
|
||||||
|
addCheckableActionToQMenuAndActionHash(gyroOptionsMenu, MenuOption::GyroLook, 0, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(gyroOptionsMenu, MenuOption::HeadMouse);
|
||||||
|
|
||||||
|
|
||||||
|
QMenu* trackingOptionsMenu = developerMenu->addMenu("Tracking Options");
|
||||||
|
addCheckableActionToQMenuAndActionHash(trackingOptionsMenu,
|
||||||
|
MenuOption::SkeletonTracking,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
appInstance->getWebcam(),
|
||||||
|
SLOT(setSkeletonTrackingOn(bool)));
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::UsePerlinFace, 0, false);
|
addCheckableActionToQMenuAndActionHash(trackingOptionsMenu,
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::LookAtVectors, 0, true);
|
MenuOption::LEDTracking,
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::LookAtIndicator, 0, true);
|
0,
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::FrameTimer);
|
false,
|
||||||
|
appInstance->getWebcam()->getGrabber(),
|
||||||
|
SLOT(setLEDTrackingOn(bool)));
|
||||||
|
|
||||||
addDisabledActionAndSeparator(developerMenu, "Testing");
|
addDisabledActionAndSeparator(developerMenu, "Testing");
|
||||||
|
|
||||||
|
QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools");
|
||||||
|
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::TestPing, 0, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer);
|
||||||
|
addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, this, SLOT(runTests()));
|
||||||
|
addActionToQMenuAndActionHash(timingMenu,
|
||||||
|
MenuOption::TreeStats,
|
||||||
|
Qt::SHIFT | Qt::Key_S,
|
||||||
|
appInstance->getVoxels(),
|
||||||
|
SLOT(collectStatsForTreesAndVBOs()));
|
||||||
|
|
||||||
QMenu* frustumMenu = developerMenu->addMenu("View Frustum Debugging Tools");
|
QMenu* frustumMenu = developerMenu->addMenu("View Frustum Debugging Tools");
|
||||||
addCheckableActionToQMenuAndActionHash(frustumMenu, MenuOption::DisplayFrustum, Qt::SHIFT | Qt::Key_F);
|
addCheckableActionToQMenuAndActionHash(frustumMenu, MenuOption::DisplayFrustum, Qt::SHIFT | Qt::Key_F);
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(frustumMenu,
|
addActionToQMenuAndActionHash(frustumMenu,
|
||||||
MenuOption::FrustumRenderMode,
|
MenuOption::FrustumRenderMode,
|
||||||
Qt::SHIFT | Qt::Key_R,
|
Qt::SHIFT | Qt::Key_R,
|
||||||
|
@ -292,12 +356,6 @@ Menu::Menu() :
|
||||||
SLOT(cycleFrustumRenderMode()));
|
SLOT(cycleFrustumRenderMode()));
|
||||||
updateFrustumRenderModeAction();
|
updateFrustumRenderModeAction();
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::RunTimingTests, 0, this, SLOT(runTests()));
|
|
||||||
addActionToQMenuAndActionHash(developerMenu,
|
|
||||||
MenuOption::TreeStats,
|
|
||||||
Qt::SHIFT | Qt::Key_S,
|
|
||||||
appInstance->getVoxels(),
|
|
||||||
SLOT(collectStatsForTreesAndVBOs()));
|
|
||||||
|
|
||||||
QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools");
|
QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools");
|
||||||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings);
|
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings);
|
||||||
|
@ -337,18 +395,6 @@ Menu::Menu() :
|
||||||
appInstance->getVoxels(),
|
appInstance->getVoxels(),
|
||||||
SLOT(falseColorizeInView()));
|
SLOT(falseColorizeInView()));
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
|
||||||
MenuOption::FalseColorOccluded,
|
|
||||||
0,
|
|
||||||
appInstance->getVoxels(),
|
|
||||||
SLOT(falseColorizeOccluded()));
|
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
|
||||||
MenuOption::FalseColorOccludedV2,
|
|
||||||
0,
|
|
||||||
appInstance->getVoxels(),
|
|
||||||
SLOT(falseColorizeOccludedV2()));
|
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||||
MenuOption::FalseColorBySource,
|
MenuOption::FalseColorBySource,
|
||||||
0,
|
0,
|
||||||
|
@ -361,32 +407,21 @@ Menu::Menu() :
|
||||||
appInstance->getVoxels(),
|
appInstance->getVoxels(),
|
||||||
SLOT(trueColorize()));
|
SLOT(trueColorize()));
|
||||||
|
|
||||||
|
addDisabledActionAndSeparator(renderDebugMenu, "Coverage Maps");
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||||
MenuOption::Webcam,
|
MenuOption::FalseColorOccluded,
|
||||||
0,
|
|
||||||
false,
|
|
||||||
appInstance->getWebcam(),
|
|
||||||
SLOT(setEnabled(bool)));
|
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(developerMenu,
|
|
||||||
MenuOption::WebcamMode,
|
|
||||||
0,
|
0,
|
||||||
appInstance->getWebcam()->getGrabber(),
|
appInstance->getVoxels(),
|
||||||
SLOT(cycleVideoSendMode()));
|
SLOT(falseColorizeOccluded()));
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
|
||||||
MenuOption::WebcamTexture,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
appInstance->getWebcam()->getGrabber(),
|
|
||||||
SLOT(setDepthOnly(bool)));
|
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||||
MenuOption::FaceshiftTCP,
|
MenuOption::FalseColorOccludedV2,
|
||||||
0,
|
0,
|
||||||
false,
|
appInstance->getVoxels(),
|
||||||
appInstance->getFaceshift(),
|
SLOT(falseColorizeOccludedV2()));
|
||||||
SLOT(setTCPEnabled(bool)));
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::CoverageMap, Qt::SHIFT | Qt::CTRL | Qt::Key_O);
|
||||||
|
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::CoverageMapV2, Qt::SHIFT | Qt::CTRL | Qt::Key_P);
|
||||||
|
|
||||||
QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools");
|
QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools");
|
||||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoAudio);
|
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoAudio);
|
||||||
|
@ -406,47 +441,38 @@ Menu::Menu() :
|
||||||
appInstance,
|
appInstance,
|
||||||
SLOT(setListenModeSingleSource()));
|
SLOT(setListenModeSingleSource()));
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::TestPing, 0, true);
|
QMenu* voxelProtoOptionsMenu = developerMenu->addMenu("Voxel Server Protocol Options");
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu,
|
||||||
MenuOption::SendVoxelColors,
|
MenuOption::SendVoxelColors,
|
||||||
0,
|
0,
|
||||||
true,
|
true,
|
||||||
appInstance->getAvatar(),
|
appInstance->getAvatar(),
|
||||||
SLOT(setWantColor(bool)));
|
SLOT(setWantColor(bool)));
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu,
|
||||||
MenuOption::LowRes,
|
MenuOption::LowRes,
|
||||||
0,
|
0,
|
||||||
true,
|
true,
|
||||||
appInstance->getAvatar(),
|
appInstance->getAvatar(),
|
||||||
SLOT(setWantLowResMoving(bool)));
|
SLOT(setWantLowResMoving(bool)));
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu,
|
||||||
MenuOption::DeltaSending,
|
MenuOption::DeltaSending,
|
||||||
0,
|
0,
|
||||||
true,
|
true,
|
||||||
appInstance->getAvatar(),
|
appInstance->getAvatar(),
|
||||||
SLOT(setWantDelta(bool)));
|
SLOT(setWantDelta(bool)));
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu,
|
||||||
MenuOption::OcclusionCulling,
|
MenuOption::OcclusionCulling,
|
||||||
Qt::SHIFT | Qt::Key_C,
|
Qt::SHIFT | Qt::Key_C,
|
||||||
true,
|
true,
|
||||||
appInstance->getAvatar(),
|
appInstance->getAvatar(),
|
||||||
SLOT(setWantOcclusionCulling(bool)));
|
SLOT(setWantOcclusionCulling(bool)));
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::CoverageMap, Qt::SHIFT | Qt::CTRL | Qt::Key_O);
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::CoverageMapV2, Qt::SHIFT | Qt::CTRL | Qt::Key_P);
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::SimulateLeapHand);
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::TestRaveGlove);
|
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::GyroLook, 0, true);
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::HeadMouse);
|
|
||||||
|
|
||||||
addDisabledActionAndSeparator(developerMenu, "Voxels");
|
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DestructiveAddVoxel);
|
|
||||||
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DestructiveAddVoxel);
|
||||||
|
|
||||||
#ifndef Q_OS_MAC
|
#ifndef Q_OS_MAC
|
||||||
QMenu* helpMenu = addMenu("Help");
|
QMenu* helpMenu = addMenu("Help");
|
||||||
QAction* helpAction = helpMenu->addAction(MenuOption::AboutApp);
|
QAction* helpAction = helpMenu->addAction(MenuOption::AboutApp);
|
||||||
|
@ -465,9 +491,9 @@ void Menu::loadSettings(QSettings* settings) {
|
||||||
settings = Application::getInstance()->getSettings();
|
settings = Application::getInstance()->getSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
_gyroCameraSensitivity = loadSetting(settings, "gyroCameraSensitivity", 0.5f);
|
|
||||||
_audioJitterBufferSamples = loadSetting(settings, "audioJitterBufferSamples", 0);
|
_audioJitterBufferSamples = loadSetting(settings, "audioJitterBufferSamples", 0);
|
||||||
_fieldOfView = loadSetting(settings, "fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES);
|
_fieldOfView = loadSetting(settings, "fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES);
|
||||||
|
_maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
||||||
|
|
||||||
settings->beginGroup("View Frustum Offset Camera");
|
settings->beginGroup("View Frustum Offset Camera");
|
||||||
// in case settings is corrupt or missing loadSetting() will check for NaN
|
// in case settings is corrupt or missing loadSetting() will check for NaN
|
||||||
|
@ -488,9 +514,9 @@ void Menu::saveSettings(QSettings* settings) {
|
||||||
settings = Application::getInstance()->getSettings();
|
settings = Application::getInstance()->getSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
settings->setValue("gyroCameraSensitivity", _gyroCameraSensitivity);
|
|
||||||
settings->setValue("audioJitterBufferSamples", _audioJitterBufferSamples);
|
settings->setValue("audioJitterBufferSamples", _audioJitterBufferSamples);
|
||||||
settings->setValue("fieldOfView", _fieldOfView);
|
settings->setValue("fieldOfView", _fieldOfView);
|
||||||
|
settings->setValue("maxVoxels", _maxVoxels);
|
||||||
settings->beginGroup("View Frustum Offset Camera");
|
settings->beginGroup("View Frustum Offset Camera");
|
||||||
settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw);
|
settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw);
|
||||||
settings->setValue("viewFrustumOffsetPitch", _viewFrustumOffset.pitch);
|
settings->setValue("viewFrustumOffsetPitch", _viewFrustumOffset.pitch);
|
||||||
|
@ -738,9 +764,6 @@ void Menu::editPreferences() {
|
||||||
QFormLayout* form = new QFormLayout();
|
QFormLayout* form = new QFormLayout();
|
||||||
layout->addLayout(form, 1);
|
layout->addLayout(form, 1);
|
||||||
|
|
||||||
QLineEdit* domainServerLineEdit = lineEditForDomainHostname();
|
|
||||||
form->addRow("Domain server:", domainServerLineEdit);
|
|
||||||
|
|
||||||
QLineEdit* avatarURL = new QLineEdit(applicationInstance->getAvatar()->getVoxels()->getVoxelURL().toString());
|
QLineEdit* avatarURL = new QLineEdit(applicationInstance->getAvatar()->getVoxels()->getVoxelURL().toString());
|
||||||
avatarURL->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
avatarURL->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||||
form->addRow("Avatar URL:", avatarURL);
|
form->addRow("Avatar URL:", avatarURL);
|
||||||
|
@ -749,16 +772,16 @@ void Menu::editPreferences() {
|
||||||
faceURL->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
faceURL->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||||
form->addRow("Face URL:", faceURL);
|
form->addRow("Face URL:", faceURL);
|
||||||
|
|
||||||
|
QSlider* pupilDilation = new QSlider(Qt::Horizontal);
|
||||||
|
pupilDilation->setValue(applicationInstance->getAvatar()->getHead().getPupilDilation() * pupilDilation->maximum());
|
||||||
|
form->addRow("Pupil Dilation:", pupilDilation);
|
||||||
|
|
||||||
QSpinBox* fieldOfView = new QSpinBox();
|
QSpinBox* fieldOfView = new QSpinBox();
|
||||||
fieldOfView->setMaximum(180);
|
fieldOfView->setMaximum(180);
|
||||||
fieldOfView->setMinimum(1);
|
fieldOfView->setMinimum(1);
|
||||||
fieldOfView->setValue(_fieldOfView);
|
fieldOfView->setValue(_fieldOfView);
|
||||||
form->addRow("Vertical Field of View (Degrees):", fieldOfView);
|
form->addRow("Vertical Field of View (Degrees):", fieldOfView);
|
||||||
|
|
||||||
QDoubleSpinBox* gyroCameraSensitivity = new QDoubleSpinBox();
|
|
||||||
gyroCameraSensitivity->setValue(_gyroCameraSensitivity);
|
|
||||||
form->addRow("Gyro Camera Sensitivity (0 - 1):", gyroCameraSensitivity);
|
|
||||||
|
|
||||||
QDoubleSpinBox* leanScale = new QDoubleSpinBox();
|
QDoubleSpinBox* leanScale = new QDoubleSpinBox();
|
||||||
leanScale->setValue(applicationInstance->getAvatar()->getLeanScale());
|
leanScale->setValue(applicationInstance->getAvatar()->getLeanScale());
|
||||||
form->addRow("Lean Scale:", leanScale);
|
form->addRow("Lean Scale:", leanScale);
|
||||||
|
@ -768,6 +791,16 @@ void Menu::editPreferences() {
|
||||||
audioJitterBufferSamples->setMinimum(-10000);
|
audioJitterBufferSamples->setMinimum(-10000);
|
||||||
audioJitterBufferSamples->setValue(_audioJitterBufferSamples);
|
audioJitterBufferSamples->setValue(_audioJitterBufferSamples);
|
||||||
form->addRow("Audio Jitter Buffer Samples (0 for automatic):", audioJitterBufferSamples);
|
form->addRow("Audio Jitter Buffer Samples (0 for automatic):", audioJitterBufferSamples);
|
||||||
|
|
||||||
|
QSpinBox* maxVoxels = new QSpinBox();
|
||||||
|
const int MAX_MAX_VOXELS = 5000000;
|
||||||
|
const int MIN_MAX_VOXELS = 0;
|
||||||
|
const int STEP_MAX_VOXELS = 50000;
|
||||||
|
maxVoxels->setMaximum(MAX_MAX_VOXELS);
|
||||||
|
maxVoxels->setMinimum(MIN_MAX_VOXELS);
|
||||||
|
maxVoxels->setSingleStep(STEP_MAX_VOXELS);
|
||||||
|
maxVoxels->setValue(_maxVoxels);
|
||||||
|
form->addRow("Maximum Voxels:", maxVoxels);
|
||||||
|
|
||||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||||
|
@ -780,8 +813,6 @@ void Menu::editPreferences() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDSHostname(domainServerLineEdit->text());
|
|
||||||
|
|
||||||
QUrl avatarVoxelURL(avatarURL->text());
|
QUrl avatarVoxelURL(avatarURL->text());
|
||||||
applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL);
|
applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL);
|
||||||
|
|
||||||
|
@ -790,7 +821,10 @@ void Menu::editPreferences() {
|
||||||
|
|
||||||
Avatar::sendAvatarURLsMessage(avatarVoxelURL, faceModelURL);
|
Avatar::sendAvatarURLsMessage(avatarVoxelURL, faceModelURL);
|
||||||
|
|
||||||
_gyroCameraSensitivity = gyroCameraSensitivity->value();
|
applicationInstance->getAvatar()->getHead().setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum());
|
||||||
|
|
||||||
|
_maxVoxels = maxVoxels->value();
|
||||||
|
applicationInstance->getVoxels()->setMaxVoxels(_maxVoxels);
|
||||||
|
|
||||||
applicationInstance->getAvatar()->setLeanScale(leanScale->value());
|
applicationInstance->getAvatar()->setLeanScale(leanScale->value());
|
||||||
|
|
||||||
|
@ -990,3 +1024,8 @@ void Menu::updateFrustumRenderModeAction() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu::switchVoxelShader() {
|
||||||
|
Application::getInstance()->getVoxels()->setUseVoxelShader(isOptionChecked(MenuOption::UseVoxelShader));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,11 +49,12 @@ public:
|
||||||
|
|
||||||
float getAudioJitterBufferSamples() const { return _audioJitterBufferSamples; }
|
float getAudioJitterBufferSamples() const { return _audioJitterBufferSamples; }
|
||||||
float getFieldOfView() const { return _fieldOfView; }
|
float getFieldOfView() const { return _fieldOfView; }
|
||||||
float getGyroCameraSensitivity() const { return _gyroCameraSensitivity; }
|
|
||||||
BandwidthDialog* getBandwidthDialog() const { return _bandwidthDialog; }
|
BandwidthDialog* getBandwidthDialog() const { return _bandwidthDialog; }
|
||||||
FrustumDrawMode getFrustumDrawMode() const { return _frustumDrawMode; }
|
FrustumDrawMode getFrustumDrawMode() const { return _frustumDrawMode; }
|
||||||
ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; }
|
ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; }
|
||||||
VoxelStatsDialog* getVoxelStatsDialog() const { return _voxelStatsDialog; }
|
VoxelStatsDialog* getVoxelStatsDialog() const { return _voxelStatsDialog; }
|
||||||
|
int getMaxVoxels() const { return _maxVoxels; }
|
||||||
|
|
||||||
|
|
||||||
void handleViewFrustumOffsetKeyModifier(int key);
|
void handleViewFrustumOffsetKeyModifier(int key);
|
||||||
|
|
||||||
|
@ -78,6 +79,7 @@ private slots:
|
||||||
void chooseVoxelPaintColor();
|
void chooseVoxelPaintColor();
|
||||||
void runTests();
|
void runTests();
|
||||||
void resetSwatchColors();
|
void resetSwatchColors();
|
||||||
|
void switchVoxelShader();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Menu* _instance;
|
static Menu* _instance;
|
||||||
|
@ -111,10 +113,10 @@ private:
|
||||||
BandwidthDialog* _bandwidthDialog;
|
BandwidthDialog* _bandwidthDialog;
|
||||||
float _fieldOfView; /// in Degrees, doesn't apply to HMD like Oculus
|
float _fieldOfView; /// in Degrees, doesn't apply to HMD like Oculus
|
||||||
FrustumDrawMode _frustumDrawMode;
|
FrustumDrawMode _frustumDrawMode;
|
||||||
float _gyroCameraSensitivity;
|
|
||||||
ViewFrustumOffset _viewFrustumOffset;
|
ViewFrustumOffset _viewFrustumOffset;
|
||||||
QActionGroup* _voxelModeActionsGroup;
|
QActionGroup* _voxelModeActionsGroup;
|
||||||
VoxelStatsDialog* _voxelStatsDialog;
|
VoxelStatsDialog* _voxelStatsDialog;
|
||||||
|
int _maxVoxels;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace MenuOption {
|
namespace MenuOption {
|
||||||
|
@ -201,9 +203,9 @@ namespace MenuOption {
|
||||||
const QString TransmitterDrive = "Transmitter Drive";
|
const QString TransmitterDrive = "Transmitter Drive";
|
||||||
const QString UsePerlinFace = "Use Perlin's Face";
|
const QString UsePerlinFace = "Use Perlin's Face";
|
||||||
const QString Quit = "Quit";
|
const QString Quit = "Quit";
|
||||||
const QString Webcam = "Webcam";
|
const QString UseVoxelShader = "Use Voxel Shader";
|
||||||
const QString WebcamMode = "Cycle Webcam Send Mode";
|
const QString UseByteNormals = "Use Byte Normals";
|
||||||
const QString WebcamTexture = "Webcam Texture";
|
const QString UseGlobalNormals = "Use Global Normals";
|
||||||
const QString Voxels = "Voxels";
|
const QString Voxels = "Voxels";
|
||||||
const QString VoxelAddMode = "Add Voxel Mode";
|
const QString VoxelAddMode = "Add Voxel Mode";
|
||||||
const QString VoxelColorMode = "Color Voxel Mode";
|
const QString VoxelColorMode = "Color Voxel Mode";
|
||||||
|
@ -214,6 +216,9 @@ namespace MenuOption {
|
||||||
const QString VoxelSelectMode = "Select Voxel Mode";
|
const QString VoxelSelectMode = "Select Voxel Mode";
|
||||||
const QString VoxelStats = "Voxel Stats";
|
const QString VoxelStats = "Voxel Stats";
|
||||||
const QString VoxelTextures = "Voxel Textures";
|
const QString VoxelTextures = "Voxel Textures";
|
||||||
|
const QString Webcam = "Webcam";
|
||||||
|
const QString WebcamMode = "Cycle Webcam Send Mode";
|
||||||
|
const QString WebcamTexture = "Webcam Texture";
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* defined(__hifi__Menu__) */
|
#endif /* defined(__hifi__Menu__) */
|
||||||
|
|
|
@ -33,9 +33,11 @@
|
||||||
#include "VoxelConstants.h"
|
#include "VoxelConstants.h"
|
||||||
#include "VoxelSystem.h"
|
#include "VoxelSystem.h"
|
||||||
|
|
||||||
float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1,
|
float identityVerticesGlobalNormals[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 };
|
||||||
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1,
|
|
||||||
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 };
|
float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, //0-7
|
||||||
|
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, //8-15
|
||||||
|
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 }; // 16-23
|
||||||
|
|
||||||
GLfloat identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1,
|
GLfloat identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1,
|
||||||
0,0,+1, 0,0,+1, 0,0,+1, 0,0,+1,
|
0,0,+1, 0,0,+1, 0,0,+1, 0,0,+1,
|
||||||
|
@ -51,6 +53,13 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z-
|
||||||
10,11,15, 10,15,14, // Y+
|
10,11,15, 10,15,14, // Y+
|
||||||
4,5,6, 4,6,7 }; // Z+
|
4,5,6, 4,6,7 }; // Z+
|
||||||
|
|
||||||
|
GLubyte identityIndicesTop[] = { 2, 3, 7, 2, 7, 6 };
|
||||||
|
GLubyte identityIndicesBottom[] = { 0, 1, 5, 0, 5, 4 };
|
||||||
|
GLubyte identityIndicesLeft[] = { 0, 7, 3, 0, 4, 7 };
|
||||||
|
GLubyte identityIndicesRight[] = { 1, 2, 6, 1, 6, 5 };
|
||||||
|
GLubyte identityIndicesFront[] = { 0, 2, 1, 0, 3, 2 };
|
||||||
|
GLubyte identityIndicesBack[] = { 4, 5, 6, 4, 6, 7 };
|
||||||
|
|
||||||
VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
|
VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
|
||||||
: NodeData(NULL),
|
: NodeData(NULL),
|
||||||
_treeScale(treeScale),
|
_treeScale(treeScale),
|
||||||
|
@ -74,6 +83,21 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
|
||||||
|
|
||||||
connect(_tree, SIGNAL(importSize(float,float,float)), SIGNAL(importSize(float,float,float)));
|
connect(_tree, SIGNAL(importSize(float,float,float)), SIGNAL(importSize(float,float,float)));
|
||||||
connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int)));
|
connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int)));
|
||||||
|
|
||||||
|
_useVoxelShader = false;
|
||||||
|
_useByteNormals = false;
|
||||||
|
_useGlobalNormals = false;
|
||||||
|
|
||||||
|
_writeVoxelShaderData = NULL;
|
||||||
|
_readVoxelShaderData = NULL;
|
||||||
|
|
||||||
|
_readVerticesArray = NULL;
|
||||||
|
_writeVerticesArray = NULL;
|
||||||
|
_readColorsArray = NULL;
|
||||||
|
_writeColorsArray = NULL;
|
||||||
|
_writeVoxelDirtyArray = NULL;
|
||||||
|
_readVoxelDirtyArray = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelSystem::nodeDeleted(VoxelNode* node) {
|
void VoxelSystem::nodeDeleted(VoxelNode* node) {
|
||||||
|
@ -119,21 +143,7 @@ void VoxelSystem::clearFreeBufferIndexes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelSystem::~VoxelSystem() {
|
VoxelSystem::~VoxelSystem() {
|
||||||
if (_initialized) {
|
cleanupVoxelMemory();
|
||||||
// Destroy glBuffers
|
|
||||||
glDeleteBuffers(1, &_vboVerticesID);
|
|
||||||
glDeleteBuffers(1, &_vboNormalsID);
|
|
||||||
glDeleteBuffers(1, &_vboColorsID);
|
|
||||||
glDeleteBuffers(1, &_vboIndicesID);
|
|
||||||
|
|
||||||
delete[] _readVerticesArray;
|
|
||||||
delete[] _writeVerticesArray;
|
|
||||||
delete[] _readColorsArray;
|
|
||||||
delete[] _writeColorsArray;
|
|
||||||
delete[] _writeVoxelDirtyArray;
|
|
||||||
delete[] _readVoxelDirtyArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete _tree;
|
delete _tree;
|
||||||
pthread_mutex_destroy(&_bufferWriteLock);
|
pthread_mutex_destroy(&_bufferWriteLock);
|
||||||
pthread_mutex_destroy(&_treeLock);
|
pthread_mutex_destroy(&_treeLock);
|
||||||
|
@ -141,6 +151,321 @@ VoxelSystem::~VoxelSystem() {
|
||||||
VoxelNode::removeDeleteHook(this);
|
VoxelNode::removeDeleteHook(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VoxelSystem::setUseByteNormals(bool useByteNormals) {
|
||||||
|
pthread_mutex_lock(&_bufferWriteLock);
|
||||||
|
bool wasInitialized = _initialized;
|
||||||
|
if (wasInitialized) {
|
||||||
|
clearAllNodesBufferIndex();
|
||||||
|
cleanupVoxelMemory();
|
||||||
|
}
|
||||||
|
_useByteNormals = useByteNormals;
|
||||||
|
if (wasInitialized) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&_bufferWriteLock);
|
||||||
|
|
||||||
|
if (wasInitialized) {
|
||||||
|
forceRedrawEntireTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelSystem::setUseGlobalNormals(bool useGlobalNormals) {
|
||||||
|
pthread_mutex_lock(&_bufferWriteLock);
|
||||||
|
bool wasInitialized = _initialized;
|
||||||
|
if (wasInitialized) {
|
||||||
|
clearAllNodesBufferIndex();
|
||||||
|
cleanupVoxelMemory();
|
||||||
|
}
|
||||||
|
_useGlobalNormals = useGlobalNormals;
|
||||||
|
if (wasInitialized) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&_bufferWriteLock);
|
||||||
|
|
||||||
|
if (wasInitialized) {
|
||||||
|
forceRedrawEntireTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelSystem::setMaxVoxels(int maxVoxels) {
|
||||||
|
pthread_mutex_lock(&_bufferWriteLock);
|
||||||
|
bool wasInitialized = _initialized;
|
||||||
|
if (wasInitialized) {
|
||||||
|
clearAllNodesBufferIndex();
|
||||||
|
cleanupVoxelMemory();
|
||||||
|
}
|
||||||
|
_maxVoxels = maxVoxels;
|
||||||
|
if (wasInitialized) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&_bufferWriteLock);
|
||||||
|
|
||||||
|
if (wasInitialized) {
|
||||||
|
forceRedrawEntireTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelSystem::setUseVoxelShader(bool useVoxelShader) {
|
||||||
|
pthread_mutex_lock(&_bufferWriteLock);
|
||||||
|
bool wasInitialized = _initialized;
|
||||||
|
if (wasInitialized) {
|
||||||
|
clearAllNodesBufferIndex();
|
||||||
|
cleanupVoxelMemory();
|
||||||
|
}
|
||||||
|
_useVoxelShader = useVoxelShader;
|
||||||
|
if (wasInitialized) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&_bufferWriteLock);
|
||||||
|
|
||||||
|
if (wasInitialized) {
|
||||||
|
forceRedrawEntireTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelSystem::cleanupVoxelMemory() {
|
||||||
|
if (_initialized) {
|
||||||
|
if (_useVoxelShader) {
|
||||||
|
// these are used when in VoxelShader mode.
|
||||||
|
glDeleteBuffers(1, &_vboVoxelsID);
|
||||||
|
glDeleteBuffers(1, &_vboVoxelsIndicesID);
|
||||||
|
|
||||||
|
delete[] _writeVoxelShaderData;
|
||||||
|
delete[] _readVoxelShaderData;
|
||||||
|
} else {
|
||||||
|
// Destroy glBuffers
|
||||||
|
glDeleteBuffers(1, &_vboVerticesID);
|
||||||
|
glDeleteBuffers(1, &_vboColorsID);
|
||||||
|
|
||||||
|
if (!_useGlobalNormals) {
|
||||||
|
glDeleteBuffers(1, &_vboNormalsID);
|
||||||
|
glDeleteBuffers(1, &_vboIndicesID);
|
||||||
|
} else {
|
||||||
|
glDeleteBuffers(1, &_vboIndicesTop);
|
||||||
|
glDeleteBuffers(1, &_vboIndicesBottom);
|
||||||
|
glDeleteBuffers(1, &_vboIndicesLeft);
|
||||||
|
glDeleteBuffers(1, &_vboIndicesRight);
|
||||||
|
glDeleteBuffers(1, &_vboIndicesFront);
|
||||||
|
glDeleteBuffers(1, &_vboIndicesBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] _readVerticesArray;
|
||||||
|
delete[] _writeVerticesArray;
|
||||||
|
delete[] _readColorsArray;
|
||||||
|
delete[] _writeColorsArray;
|
||||||
|
}
|
||||||
|
delete[] _writeVoxelDirtyArray;
|
||||||
|
delete[] _readVoxelDirtyArray;
|
||||||
|
}
|
||||||
|
_initialized = false; // no longer initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]) {
|
||||||
|
GLuint* indicesArray = new GLuint[INDICES_PER_FACE * _maxVoxels];
|
||||||
|
|
||||||
|
// populate the indicesArray
|
||||||
|
// this will not change given new voxels, so we can set it all up now
|
||||||
|
for (int n = 0; n < _maxVoxels; n++) {
|
||||||
|
// fill the indices array
|
||||||
|
int voxelIndexOffset = n * INDICES_PER_FACE;
|
||||||
|
GLuint* currentIndicesPos = indicesArray + voxelIndexOffset;
|
||||||
|
int startIndex = (n * GLOBAL_NORMALS_VERTICES_PER_VOXEL);
|
||||||
|
|
||||||
|
for (int i = 0; i < INDICES_PER_FACE; i++) {
|
||||||
|
// add indices for this side of the cube
|
||||||
|
currentIndicesPos[i] = startIndex + faceIdentityIndices[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glGenBuffers(1, &faceVBOID);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, faceVBOID);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||||
|
INDICES_PER_FACE * sizeof(GLuint) * _maxVoxels,
|
||||||
|
indicesArray, GL_STATIC_DRAW);
|
||||||
|
_memoryUsageVBO += INDICES_PER_FACE * sizeof(GLuint) * _maxVoxels;
|
||||||
|
|
||||||
|
// delete the indices and normals arrays that are no longer needed
|
||||||
|
delete[] indicesArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelSystem::initVoxelMemory() {
|
||||||
|
_initialMemoryUsageGPU = getFreeMemoryGPU();
|
||||||
|
_memoryUsageRAM = 0;
|
||||||
|
_memoryUsageVBO = 0; // our VBO allocations as we know them
|
||||||
|
if (_useVoxelShader) {
|
||||||
|
qDebug("Using Voxel Shader...\n");
|
||||||
|
GLuint* indicesArray = new GLuint[_maxVoxels];
|
||||||
|
|
||||||
|
// populate the indicesArray
|
||||||
|
// this will not change given new voxels, so we can set it all up now
|
||||||
|
for (int n = 0; n < _maxVoxels; n++) {
|
||||||
|
indicesArray[n] = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind the indices VBO to the actual indices array
|
||||||
|
glGenBuffers(1, &_vboVoxelsIndicesID);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * _maxVoxels, indicesArray, GL_STATIC_DRAW);
|
||||||
|
_memoryUsageVBO += sizeof(GLuint) * _maxVoxels;
|
||||||
|
|
||||||
|
glGenBuffers(1, &_vboVoxelsID);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, _maxVoxels * sizeof(VoxelShaderVBOData), NULL, GL_DYNAMIC_DRAW);
|
||||||
|
_memoryUsageVBO += _maxVoxels * sizeof(VoxelShaderVBOData);
|
||||||
|
|
||||||
|
// delete the indices and normals arrays that are no longer needed
|
||||||
|
delete[] indicesArray;
|
||||||
|
|
||||||
|
// we will track individual dirty sections with these arrays of bools
|
||||||
|
_writeVoxelDirtyArray = new bool[_maxVoxels];
|
||||||
|
memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
|
||||||
|
_memoryUsageRAM += (_maxVoxels * sizeof(bool));
|
||||||
|
|
||||||
|
_readVoxelDirtyArray = new bool[_maxVoxels];
|
||||||
|
memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
|
||||||
|
_memoryUsageRAM += (_maxVoxels * sizeof(bool));
|
||||||
|
|
||||||
|
// prep the data structures for incoming voxel data
|
||||||
|
_writeVoxelShaderData = new VoxelShaderVBOData[_maxVoxels];
|
||||||
|
_memoryUsageRAM += (sizeof(VoxelShaderVBOData) * _maxVoxels);
|
||||||
|
|
||||||
|
_readVoxelShaderData = new VoxelShaderVBOData[_maxVoxels];
|
||||||
|
_memoryUsageRAM += (sizeof(VoxelShaderVBOData) * _maxVoxels);
|
||||||
|
} else {
|
||||||
|
if (_useGlobalNormals) {
|
||||||
|
// Global Normals mode uses a technique of not including normals on any voxel vertices, and instead
|
||||||
|
// rendering the voxel faces in 6 passes that use a global call to glNormal3f()
|
||||||
|
qDebug("Using Global Normals...\n");
|
||||||
|
setupFaceIndices(_vboIndicesTop, identityIndicesTop);
|
||||||
|
setupFaceIndices(_vboIndicesBottom, identityIndicesBottom);
|
||||||
|
setupFaceIndices(_vboIndicesLeft, identityIndicesLeft);
|
||||||
|
setupFaceIndices(_vboIndicesRight, identityIndicesRight);
|
||||||
|
setupFaceIndices(_vboIndicesFront, identityIndicesFront);
|
||||||
|
setupFaceIndices(_vboIndicesBack, identityIndicesBack);
|
||||||
|
} else {
|
||||||
|
if (_useByteNormals) {
|
||||||
|
qDebug("Using Byte Normals...\n");
|
||||||
|
GLbyte* normalsArray = new GLbyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels];
|
||||||
|
GLbyte* normalsArrayEndPointer = normalsArray;
|
||||||
|
|
||||||
|
// populate the normalsArray
|
||||||
|
for (int n = 0; n < _maxVoxels; n++) {
|
||||||
|
for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) {
|
||||||
|
*(normalsArrayEndPointer++) = (identityNormals[i] * CHAR_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VBO for the normalsArray
|
||||||
|
glGenBuffers(1, &_vboNormalsID);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER,
|
||||||
|
VERTEX_POINTS_PER_VOXEL * sizeof(GLbyte) * _maxVoxels,
|
||||||
|
normalsArray, GL_STATIC_DRAW);
|
||||||
|
_memoryUsageVBO += VERTEX_POINTS_PER_VOXEL * sizeof(GLbyte) * _maxVoxels;
|
||||||
|
|
||||||
|
// delete the indices and normals arrays that are no longer needed
|
||||||
|
delete[] normalsArray;
|
||||||
|
} else {
|
||||||
|
qDebug("Using Float Normals...\n");
|
||||||
|
GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels];
|
||||||
|
GLfloat* normalsArrayEndPointer = normalsArray;
|
||||||
|
|
||||||
|
// populate the normalsArray
|
||||||
|
for (int n = 0; n < _maxVoxels; n++) {
|
||||||
|
for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) {
|
||||||
|
*(normalsArrayEndPointer++) = identityNormals[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VBO for the normalsArray
|
||||||
|
glGenBuffers(1, &_vboNormalsID);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER,
|
||||||
|
VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels,
|
||||||
|
normalsArray, GL_STATIC_DRAW);
|
||||||
|
_memoryUsageVBO += VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels;
|
||||||
|
|
||||||
|
// delete the indices and normals arrays that are no longer needed
|
||||||
|
delete[] normalsArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * _maxVoxels];
|
||||||
|
|
||||||
|
// populate the indicesArray
|
||||||
|
// this will not change given new voxels, so we can set it all up now
|
||||||
|
for (int n = 0; n < _maxVoxels; n++) {
|
||||||
|
// fill the indices array
|
||||||
|
int voxelIndexOffset = n * INDICES_PER_VOXEL;
|
||||||
|
GLuint* currentIndicesPos = indicesArray + voxelIndexOffset;
|
||||||
|
int startIndex = (n * VERTICES_PER_VOXEL);
|
||||||
|
|
||||||
|
for (int i = 0; i < INDICES_PER_VOXEL; i++) {
|
||||||
|
// add indices for this side of the cube
|
||||||
|
currentIndicesPos[i] = startIndex + identityIndices[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VBO for the indicesArray
|
||||||
|
glGenBuffers(1, &_vboIndicesID);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||||
|
INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels,
|
||||||
|
indicesArray, GL_STATIC_DRAW);
|
||||||
|
_memoryUsageVBO += INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels;
|
||||||
|
|
||||||
|
// delete the indices and normals arrays that are no longer needed
|
||||||
|
delete[] indicesArray;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depending on if we're using per vertex normals, we will need more or less vertex points per voxel
|
||||||
|
int vertexPointsPerVoxel = _useGlobalNormals ? GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL : VERTEX_POINTS_PER_VOXEL;
|
||||||
|
glGenBuffers(1, &_vboVerticesID);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);
|
||||||
|
_memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels;
|
||||||
|
|
||||||
|
// VBO for colorsArray
|
||||||
|
glGenBuffers(1, &_vboColorsID);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);
|
||||||
|
_memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels;
|
||||||
|
|
||||||
|
// we will track individual dirty sections with these arrays of bools
|
||||||
|
_writeVoxelDirtyArray = new bool[_maxVoxels];
|
||||||
|
memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
|
||||||
|
_memoryUsageRAM += (sizeof(bool) * _maxVoxels);
|
||||||
|
|
||||||
|
_readVoxelDirtyArray = new bool[_maxVoxels];
|
||||||
|
memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
|
||||||
|
_memoryUsageRAM += (sizeof(bool) * _maxVoxels);
|
||||||
|
|
||||||
|
// prep the data structures for incoming voxel data
|
||||||
|
_writeVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels];
|
||||||
|
_memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels);
|
||||||
|
_readVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels];
|
||||||
|
_memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels);
|
||||||
|
|
||||||
|
_writeColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels];
|
||||||
|
_memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels);
|
||||||
|
_readColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels];
|
||||||
|
_memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels);
|
||||||
|
|
||||||
|
|
||||||
|
// create our simple fragment shader if we're the first system to init
|
||||||
|
if (!_perlinModulateProgram.isLinked()) {
|
||||||
|
switchToResourcesParentIfRequired();
|
||||||
|
_perlinModulateProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/perlin_modulate.vert");
|
||||||
|
_perlinModulateProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/perlin_modulate.frag");
|
||||||
|
_perlinModulateProgram.link();
|
||||||
|
|
||||||
|
_perlinModulateProgram.bind();
|
||||||
|
_perlinModulateProgram.setUniformValue("permutationNormalTexture", 0);
|
||||||
|
_perlinModulateProgram.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
||||||
_tree->loadVoxelsFile(fileName, wantColorRandomizer);
|
_tree->loadVoxelsFile(fileName, wantColorRandomizer);
|
||||||
setupNewVoxelsForDrawing();
|
setupNewVoxelsForDrawing();
|
||||||
|
@ -398,18 +723,27 @@ void VoxelSystem::copyWrittenDataToReadArraysPartialVBOs() {
|
||||||
|
|
||||||
void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
|
void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
|
||||||
int segmentLength = (segmentEnd - segmentStart) + 1;
|
int segmentLength = (segmentEnd - segmentStart) + 1;
|
||||||
|
if (_useVoxelShader) {
|
||||||
|
GLsizeiptr segmentSizeBytes = segmentLength * sizeof(VoxelShaderVBOData);
|
||||||
|
void* readDataAt = &_readVoxelShaderData[segmentStart];
|
||||||
|
void* writeDataAt = &_writeVoxelShaderData[segmentStart];
|
||||||
|
memcpy(readDataAt, writeDataAt, segmentSizeBytes);
|
||||||
|
} else {
|
||||||
|
// Depending on if we're using per vertex normals, we will need more or less vertex points per voxel
|
||||||
|
int vertexPointsPerVoxel = _useGlobalNormals ? GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL : VERTEX_POINTS_PER_VOXEL;
|
||||||
|
|
||||||
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat);
|
||||||
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat);
|
||||||
GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * vertexPointsPerVoxel);
|
||||||
GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * vertexPointsPerVoxel);
|
||||||
memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes);
|
memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes);
|
||||||
|
|
||||||
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte);
|
||||||
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte);
|
||||||
GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
GLubyte* readColorsAt = _readColorsArray + (segmentStart * vertexPointsPerVoxel);
|
||||||
GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * vertexPointsPerVoxel);
|
||||||
memcpy(readColorsAt, writeColorsAt, segmentSizeBytes);
|
memcpy(readColorsAt, writeColorsAt, segmentSizeBytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) {
|
void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) {
|
||||||
|
@ -532,11 +866,34 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) {
|
||||||
|
|
||||||
void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex,
|
void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex,
|
||||||
float voxelScale, const nodeColor& color) {
|
float voxelScale, const nodeColor& color) {
|
||||||
for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) {
|
|
||||||
GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
if (_useVoxelShader) {
|
||||||
GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
if (_writeVoxelShaderData) {
|
||||||
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
VoxelShaderVBOData* writeVerticesAt = &_writeVoxelShaderData[nodeIndex];
|
||||||
*(writeColorsAt +j) = color[j % 3];
|
writeVerticesAt->x = startVertex.x * TREE_SCALE;
|
||||||
|
writeVerticesAt->y = startVertex.y * TREE_SCALE;
|
||||||
|
writeVerticesAt->z = startVertex.z * TREE_SCALE;
|
||||||
|
writeVerticesAt->s = voxelScale * TREE_SCALE;
|
||||||
|
writeVerticesAt->r = color[RED_INDEX];
|
||||||
|
writeVerticesAt->g = color[GREEN_INDEX];
|
||||||
|
writeVerticesAt->b = color[BLUE_INDEX];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_writeVerticesArray && _writeColorsArray) {
|
||||||
|
int vertexPointsPerVoxel = _useGlobalNormals ? GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL : VERTEX_POINTS_PER_VOXEL;
|
||||||
|
for (int j = 0; j < vertexPointsPerVoxel; j++ ) {
|
||||||
|
GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * vertexPointsPerVoxel);
|
||||||
|
GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * vertexPointsPerVoxel);
|
||||||
|
|
||||||
|
if (_useGlobalNormals) {
|
||||||
|
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVerticesGlobalNormals[j] * voxelScale);
|
||||||
|
} else {
|
||||||
|
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
*(writeColorsAt +j) = color[j % 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,86 +920,8 @@ void VoxelSystem::init() {
|
||||||
_voxelsInWriteArrays = 0;
|
_voxelsInWriteArrays = 0;
|
||||||
_voxelsInReadArrays = 0;
|
_voxelsInReadArrays = 0;
|
||||||
|
|
||||||
GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * _maxVoxels];
|
|
||||||
|
|
||||||
// populate the indicesArray
|
|
||||||
// this will not change given new voxels, so we can set it all up now
|
|
||||||
for (int n = 0; n < _maxVoxels; n++) {
|
|
||||||
// fill the indices array
|
|
||||||
int voxelIndexOffset = n * INDICES_PER_VOXEL;
|
|
||||||
GLuint* currentIndicesPos = indicesArray + voxelIndexOffset;
|
|
||||||
int startIndex = (n * VERTICES_PER_VOXEL);
|
|
||||||
|
|
||||||
for (int i = 0; i < INDICES_PER_VOXEL; i++) {
|
|
||||||
// add indices for this side of the cube
|
|
||||||
currentIndicesPos[i] = startIndex + identityIndices[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels];
|
|
||||||
GLfloat* normalsArrayEndPointer = normalsArray;
|
|
||||||
|
|
||||||
// populate the normalsArray
|
|
||||||
for (int n = 0; n < _maxVoxels; n++) {
|
|
||||||
for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) {
|
|
||||||
*(normalsArrayEndPointer++) = identityNormals[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VBO for the verticesArray
|
// VBO for the verticesArray
|
||||||
glGenBuffers(1, &_vboVerticesID);
|
initVoxelMemory();
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
// VBO for the normalsArray
|
|
||||||
glGenBuffers(1, &_vboNormalsID);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER,
|
|
||||||
VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels,
|
|
||||||
normalsArray, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
// VBO for colorsArray
|
|
||||||
glGenBuffers(1, &_vboColorsID);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
// VBO for the indicesArray
|
|
||||||
glGenBuffers(1, &_vboIndicesID);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
|
||||||
INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels,
|
|
||||||
indicesArray, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
// delete the indices and normals arrays that are no longer needed
|
|
||||||
delete[] indicesArray;
|
|
||||||
delete[] normalsArray;
|
|
||||||
|
|
||||||
|
|
||||||
// we will track individual dirty sections with these arrays of bools
|
|
||||||
_writeVoxelDirtyArray = new bool[_maxVoxels];
|
|
||||||
memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
|
|
||||||
_readVoxelDirtyArray = new bool[_maxVoxels];
|
|
||||||
memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
|
|
||||||
|
|
||||||
// prep the data structures for incoming voxel data
|
|
||||||
_writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels];
|
|
||||||
_readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels];
|
|
||||||
|
|
||||||
_writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels];
|
|
||||||
_readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels];
|
|
||||||
|
|
||||||
|
|
||||||
// create our simple fragment shader if we're the first system to init
|
|
||||||
if (!_perlinModulateProgram.isLinked()) {
|
|
||||||
switchToResourcesParentIfRequired();
|
|
||||||
_perlinModulateProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/perlin_modulate.vert");
|
|
||||||
_perlinModulateProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/perlin_modulate.frag");
|
|
||||||
_perlinModulateProgram.link();
|
|
||||||
|
|
||||||
_perlinModulateProgram.bind();
|
|
||||||
_perlinModulateProgram.setUniformValue("permutationNormalTexture", 0);
|
|
||||||
_perlinModulateProgram.release();
|
|
||||||
}
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,17 +993,28 @@ void VoxelSystem::updateVBOs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
|
void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
|
||||||
int segmentLength = (segmentEnd - segmentStart) + 1;
|
if (_useVoxelShader) {
|
||||||
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
int segmentLength = (segmentEnd - segmentStart) + 1;
|
||||||
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
GLintptr segmentStartAt = segmentStart * sizeof(VoxelShaderVBOData);
|
||||||
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
GLsizeiptr segmentSizeBytes = segmentLength * sizeof(VoxelShaderVBOData);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
void* readVerticesFrom = &_readVoxelShaderData[segmentStart];
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
|
||||||
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID);
|
||||||
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||||
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
} else {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
int vertexPointsPerVoxel = _useGlobalNormals ? GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL : VERTEX_POINTS_PER_VOXEL;
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
|
int segmentLength = (segmentEnd - segmentStart) + 1;
|
||||||
|
GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat);
|
||||||
|
GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat);
|
||||||
|
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * vertexPointsPerVoxel);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||||
|
segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte);
|
||||||
|
segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte);
|
||||||
|
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * vertexPointsPerVoxel);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelSystem::render(bool texture) {
|
void VoxelSystem::render(bool texture) {
|
||||||
|
@ -734,43 +1024,116 @@ void VoxelSystem::render(bool texture) {
|
||||||
pthread_mutex_lock(&_bufferWriteLock);
|
pthread_mutex_lock(&_bufferWriteLock);
|
||||||
|
|
||||||
updateVBOs();
|
updateVBOs();
|
||||||
|
|
||||||
|
if (_useVoxelShader) {
|
||||||
|
|
||||||
// tell OpenGL where to find vertex and color information
|
Application::getInstance()->getVoxelShader().begin();
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glEnableClientState(GL_NORMAL_ARRAY);
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
//Define this somewhere in your header file
|
||||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
#define BUFFER_OFFSET(i) ((void*)(i))
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID);
|
||||||
glNormalPointer(GL_FLOAT, 0, 0);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glVertexPointer(3, GL_FLOAT, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices
|
||||||
|
int loc = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn");
|
||||||
|
glEnableVertexAttribArray(loc);
|
||||||
|
glVertexAttribPointer(loc, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float)));
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(4*sizeof(float)));//The starting point of colors
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID);
|
||||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
glDrawElements(GL_POINTS, _voxelsInReadArrays, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); //The starting point of the IBO
|
||||||
|
|
||||||
applyScaleAndBindProgram(texture);
|
// deactivate vertex and color arrays after drawing
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
|
// bind with 0 to switch back to normal operation
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
Application::getInstance()->getVoxelShader().end();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// tell OpenGL where to find vertex and color information
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||||
|
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||||
|
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||||
|
|
||||||
|
if (!_useGlobalNormals) {
|
||||||
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
||||||
|
glNormalPointer((_useByteNormals ? GL_BYTE : GL_FLOAT), 0, 0);
|
||||||
|
} else {
|
||||||
|
glNormal3f(0,1.0f,0); // hack for now
|
||||||
|
}
|
||||||
|
|
||||||
|
applyScaleAndBindProgram(texture);
|
||||||
|
|
||||||
// for performance, enable backface culling
|
// for performance, enable backface culling
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
// draw the number of voxels we have
|
if (!_useGlobalNormals) {
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
// draw the number of voxels we have
|
||||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
||||||
36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||||
|
36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
} else {
|
||||||
|
// draw voxels in 6 passes
|
||||||
|
|
||||||
glDisable(GL_CULL_FACE);
|
glNormal3f(0,1.0f,0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop);
|
||||||
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
removeScaleAndReleaseProgram(texture);
|
glNormal3f(0,-1.0f,0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom);
|
||||||
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
|
glNormal3f(-1.0f,0,0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft);
|
||||||
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
|
glNormal3f(1.0f,0,0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight);
|
||||||
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
|
glNormal3f(0,0,-1.0f);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront);
|
||||||
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
|
glNormal3f(0,0,1.0f);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBack);
|
||||||
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
removeScaleAndReleaseProgram(texture);
|
||||||
|
|
||||||
// deactivate vertex and color arrays after drawing
|
// deactivate vertex and color arrays after drawing
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
glDisableClientState(GL_NORMAL_ARRAY);
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
|
||||||
|
|
||||||
// bind with 0 to switch back to normal operation
|
if (!_useGlobalNormals) {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glDisableClientState(GL_NORMAL_ARRAY);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
}
|
||||||
|
|
||||||
|
// bind with 0 to switch back to normal operation
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&_bufferWriteLock);
|
pthread_mutex_unlock(&_bufferWriteLock);
|
||||||
}
|
}
|
||||||
|
@ -804,6 +1167,34 @@ void VoxelSystem::killLocalVoxels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool VoxelSystem::clearAllNodesBufferIndexOperation(VoxelNode* node, void* extraData) {
|
||||||
|
_nodeCount++;
|
||||||
|
node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelSystem::clearAllNodesBufferIndex() {
|
||||||
|
_nodeCount = 0;
|
||||||
|
_tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation);
|
||||||
|
qDebug("clearing buffer index of %d nodes\n", _nodeCount);
|
||||||
|
_tree->setDirtyBit();
|
||||||
|
setupNewVoxelsForDrawing();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VoxelSystem::forceRedrawEntireTreeOperation(VoxelNode* node, void* extraData) {
|
||||||
|
_nodeCount++;
|
||||||
|
node->setDirtyBit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelSystem::forceRedrawEntireTree() {
|
||||||
|
_nodeCount = 0;
|
||||||
|
_tree->recurseTreeWithOperation(forceRedrawEntireTreeOperation);
|
||||||
|
qDebug("forcing redraw of %d nodes\n", _nodeCount);
|
||||||
|
_tree->setDirtyBit();
|
||||||
|
setupNewVoxelsForDrawing();
|
||||||
|
}
|
||||||
|
|
||||||
bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) {
|
bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) {
|
||||||
_nodeCount++;
|
_nodeCount++;
|
||||||
if (node->isColored()) {
|
if (node->isColored()) {
|
||||||
|
@ -1203,7 +1594,7 @@ public:
|
||||||
duplicateVBOIndex(0),
|
duplicateVBOIndex(0),
|
||||||
leafNodes(0)
|
leafNodes(0)
|
||||||
{
|
{
|
||||||
memset(hasIndexFound, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool));
|
memset(hasIndexFound, false, DEFAULT_MAX_VOXELS_PER_SYSTEM * sizeof(bool));
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned long totalNodes;
|
unsigned long totalNodes;
|
||||||
|
@ -1218,7 +1609,7 @@ public:
|
||||||
|
|
||||||
unsigned long expectedMax;
|
unsigned long expectedMax;
|
||||||
|
|
||||||
bool hasIndexFound[MAX_VOXELS_PER_SYSTEM];
|
bool hasIndexFound[DEFAULT_MAX_VOXELS_PER_SYSTEM];
|
||||||
};
|
};
|
||||||
|
|
||||||
bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData) {
|
bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData) {
|
||||||
|
@ -1293,7 +1684,7 @@ void VoxelSystem::collectStatsForTreesAndVBOs() {
|
||||||
glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN;
|
glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN;
|
||||||
glBufferIndex maxInVBO = 0;
|
glBufferIndex maxInVBO = 0;
|
||||||
|
|
||||||
for (glBufferIndex i = 0; i < MAX_VOXELS_PER_SYSTEM; i++) {
|
for (glBufferIndex i = 0; i < DEFAULT_MAX_VOXELS_PER_SYSTEM; i++) {
|
||||||
if (args.hasIndexFound[i]) {
|
if (args.hasIndexFound[i]) {
|
||||||
minInVBO = std::min(minInVBO,i);
|
minInVBO = std::min(minInVBO,i);
|
||||||
maxInVBO = std::max(maxInVBO,i);
|
maxInVBO = std::max(maxInVBO,i);
|
||||||
|
@ -1622,7 +2013,7 @@ void VoxelSystem::falseColorizeOccludedV2() {
|
||||||
void VoxelSystem::nodeAdded(Node* node) {
|
void VoxelSystem::nodeAdded(Node* node) {
|
||||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
uint16_t nodeID = node->getNodeID();
|
uint16_t nodeID = node->getNodeID();
|
||||||
printf("VoxelSystem... voxel server %u added...\n", nodeID);
|
qDebug("VoxelSystem... voxel server %u added...\n", nodeID);
|
||||||
_voxelServerCount++;
|
_voxelServerCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1645,7 +2036,7 @@ void VoxelSystem::nodeKilled(Node* node) {
|
||||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
_voxelServerCount--;
|
_voxelServerCount--;
|
||||||
uint16_t nodeID = node->getNodeID();
|
uint16_t nodeID = node->getNodeID();
|
||||||
printf("VoxelSystem... voxel server %u removed...\n", nodeID);
|
qDebug("VoxelSystem... voxel server %u removed...\n", nodeID);
|
||||||
|
|
||||||
if (_voxelServerCount > 0) {
|
if (_voxelServerCount > 0) {
|
||||||
// Kill any voxels from the local tree that match this nodeID
|
// Kill any voxels from the local tree that match this nodeID
|
||||||
|
@ -1661,3 +2052,58 @@ void VoxelSystem::nodeKilled(Node* node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long VoxelSystem::getFreeMemoryGPU() {
|
||||||
|
// We can't ask all GPUs how much memory they have in use, but we can ask them about how much is free.
|
||||||
|
// So, we can record the free memory before we create our VBOs and the free memory after, and get a basic
|
||||||
|
// idea how how much we're using.
|
||||||
|
|
||||||
|
_hasMemoryUsageGPU = false; // assume the worst
|
||||||
|
unsigned long freeMemory = 0;
|
||||||
|
const int NUM_RESULTS = 4; // see notes, these APIs return up to 4 results
|
||||||
|
GLint results[NUM_RESULTS] = { 0, 0, 0, 0};
|
||||||
|
|
||||||
|
// ATI
|
||||||
|
// http://www.opengl.org/registry/specs/ATI/meminfo.txt
|
||||||
|
//
|
||||||
|
// TEXTURE_FREE_MEMORY_ATI 0x87FC
|
||||||
|
// RENDERBUFFER_FREE_MEMORY_ATI 0x87FD
|
||||||
|
const GLenum VBO_FREE_MEMORY_ATI = 0x87FB;
|
||||||
|
glGetIntegerv(VBO_FREE_MEMORY_ATI, &results[0]);
|
||||||
|
GLenum errorATI = glGetError();
|
||||||
|
|
||||||
|
if (errorATI == GL_NO_ERROR) {
|
||||||
|
_hasMemoryUsageGPU = true;
|
||||||
|
freeMemory = results[0];
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// NVIDIA
|
||||||
|
// http://developer.download.nvidia.com/opengl/specs/GL_NVX_gpu_memory_info.txt
|
||||||
|
//
|
||||||
|
//const GLenum GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX = 0x9047;
|
||||||
|
//const GLenum GPU_MEMORY_INFO_EVICTION_COUNT_NVX = 0x904A;
|
||||||
|
//const GLenum GPU_MEMORY_INFO_EVICTED_MEMORY_NVX = 0x904B;
|
||||||
|
//const GLenum GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX = 0x9048;
|
||||||
|
|
||||||
|
const GLenum GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX = 0x9049;
|
||||||
|
results[0] = 0;
|
||||||
|
glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &results[0]);
|
||||||
|
freeMemory += results[0];
|
||||||
|
GLenum errorNVIDIA = glGetError();
|
||||||
|
|
||||||
|
if (errorNVIDIA == GL_NO_ERROR) {
|
||||||
|
_hasMemoryUsageGPU = true;
|
||||||
|
freeMemory = results[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned long BYTES_PER_KBYTE = 1024;
|
||||||
|
return freeMemory * BYTES_PER_KBYTE; // API results in KB, we want it in bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long VoxelSystem::getVoxelMemoryUsageGPU() {
|
||||||
|
unsigned long currentFreeMemory = getFreeMemoryGPU();
|
||||||
|
return (_initialMemoryUsageGPU - currentFreeMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,15 +23,24 @@
|
||||||
#include "Camera.h"
|
#include "Camera.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "world.h"
|
#include "world.h"
|
||||||
|
#include "renderer/VoxelShader.h"
|
||||||
|
|
||||||
class ProgramObject;
|
class ProgramObject;
|
||||||
|
|
||||||
const int NUM_CHILDREN = 8;
|
const int NUM_CHILDREN = 8;
|
||||||
|
|
||||||
|
struct VoxelShaderVBOData
|
||||||
|
{
|
||||||
|
float x, y, z; // position
|
||||||
|
float s; // size
|
||||||
|
unsigned char r,g,b; // color
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class VoxelSystem : public NodeData, public VoxelNodeDeleteHook, public NodeListHook {
|
class VoxelSystem : public NodeData, public VoxelNodeDeleteHook, public NodeListHook {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = MAX_VOXELS_PER_SYSTEM);
|
VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
||||||
~VoxelSystem();
|
~VoxelSystem();
|
||||||
|
|
||||||
void setDataSourceID(int dataSourceID) { _dataSourceID = dataSourceID; }
|
void setDataSourceID(int dataSourceID) { _dataSourceID = dataSourceID; }
|
||||||
|
@ -56,6 +65,14 @@ public:
|
||||||
bool readFromSquareARGB32Pixels(const char* filename);
|
bool readFromSquareARGB32Pixels(const char* filename);
|
||||||
bool readFromSchematicFile(const char* filename);
|
bool readFromSchematicFile(const char* filename);
|
||||||
|
|
||||||
|
void setUseVoxelShader(bool useVoxelShader);
|
||||||
|
|
||||||
|
void setMaxVoxels(int maxVoxels);
|
||||||
|
long int getMaxVoxels() const { return _maxVoxels; }
|
||||||
|
unsigned long getVoxelMemoryUsageRAM() const { return _memoryUsageRAM; }
|
||||||
|
unsigned long getVoxelMemoryUsageVBO() const { return _memoryUsageVBO; }
|
||||||
|
bool hasVoxelMemoryUsageGPU() const { return _hasMemoryUsageGPU; }
|
||||||
|
unsigned long getVoxelMemoryUsageGPU();
|
||||||
long int getVoxelsCreated();
|
long int getVoxelsCreated();
|
||||||
long int getVoxelsColored();
|
long int getVoxelsColored();
|
||||||
long int getVoxelsBytesRead();
|
long int getVoxelsBytesRead();
|
||||||
|
@ -113,8 +130,12 @@ public slots:
|
||||||
void falseColorizeOccluded();
|
void falseColorizeOccluded();
|
||||||
void falseColorizeOccludedV2();
|
void falseColorizeOccludedV2();
|
||||||
void falseColorizeBySource();
|
void falseColorizeBySource();
|
||||||
|
void forceRedrawEntireTree();
|
||||||
|
void clearAllNodesBufferIndex();
|
||||||
|
|
||||||
void cancelImport();
|
void cancelImport();
|
||||||
|
void setUseByteNormals(bool useByteNormals);
|
||||||
|
void setUseGlobalNormals(bool useGlobalNormals);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float _treeScale;
|
float _treeScale;
|
||||||
|
@ -158,6 +179,8 @@ private:
|
||||||
static bool falseColorizeOccludedV2Operation(VoxelNode* node, void* extraData);
|
static bool falseColorizeOccludedV2Operation(VoxelNode* node, void* extraData);
|
||||||
static bool falseColorizeBySourceOperation(VoxelNode* node, void* extraData);
|
static bool falseColorizeBySourceOperation(VoxelNode* node, void* extraData);
|
||||||
static bool killSourceVoxelsOperation(VoxelNode* node, void* extraData);
|
static bool killSourceVoxelsOperation(VoxelNode* node, void* extraData);
|
||||||
|
static bool forceRedrawEntireTreeOperation(VoxelNode* node, void* extraData);
|
||||||
|
static bool clearAllNodesBufferIndexOperation(VoxelNode* node, void* extraData);
|
||||||
|
|
||||||
int updateNodeInArraysAsFullVBO(VoxelNode* node);
|
int updateNodeInArraysAsFullVBO(VoxelNode* node);
|
||||||
int updateNodeInArraysAsPartialVBO(VoxelNode* node);
|
int updateNodeInArraysAsPartialVBO(VoxelNode* node);
|
||||||
|
@ -167,6 +190,8 @@ private:
|
||||||
|
|
||||||
void updateVBOs();
|
void updateVBOs();
|
||||||
|
|
||||||
|
unsigned long getFreeMemoryGPU();
|
||||||
|
|
||||||
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
|
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
|
||||||
static float _maxDistance;
|
static float _maxDistance;
|
||||||
static float _minDistance;
|
static float _minDistance;
|
||||||
|
@ -190,10 +215,30 @@ private:
|
||||||
uint64_t _lastViewCulling;
|
uint64_t _lastViewCulling;
|
||||||
int _lastViewCullingElapsed;
|
int _lastViewCullingElapsed;
|
||||||
|
|
||||||
|
void initVoxelMemory();
|
||||||
|
void cleanupVoxelMemory();
|
||||||
|
|
||||||
|
bool _useByteNormals;
|
||||||
|
bool _useGlobalNormals;
|
||||||
|
|
||||||
|
bool _useVoxelShader;
|
||||||
|
GLuint _vboVoxelsID; /// when using voxel shader, we'll use this VBO
|
||||||
|
GLuint _vboVoxelsIndicesID; /// when using voxel shader, we'll use this VBO for our indexes
|
||||||
|
VoxelShaderVBOData* _writeVoxelShaderData;
|
||||||
|
VoxelShaderVBOData* _readVoxelShaderData;
|
||||||
|
|
||||||
GLuint _vboVerticesID;
|
GLuint _vboVerticesID;
|
||||||
GLuint _vboNormalsID;
|
GLuint _vboNormalsID;
|
||||||
GLuint _vboColorsID;
|
GLuint _vboColorsID;
|
||||||
GLuint _vboIndicesID;
|
GLuint _vboIndicesID;
|
||||||
|
|
||||||
|
GLuint _vboIndicesTop;
|
||||||
|
GLuint _vboIndicesBottom;
|
||||||
|
GLuint _vboIndicesLeft;
|
||||||
|
GLuint _vboIndicesRight;
|
||||||
|
GLuint _vboIndicesFront;
|
||||||
|
GLuint _vboIndicesBack;
|
||||||
|
|
||||||
pthread_mutex_t _bufferWriteLock;
|
pthread_mutex_t _bufferWriteLock;
|
||||||
pthread_mutex_t _treeLock;
|
pthread_mutex_t _treeLock;
|
||||||
|
|
||||||
|
@ -201,6 +246,8 @@ private:
|
||||||
ViewFrustum _lastStableViewFrustum;
|
ViewFrustum _lastStableViewFrustum;
|
||||||
ViewFrustum* _viewFrustum;
|
ViewFrustum* _viewFrustum;
|
||||||
|
|
||||||
|
void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]);
|
||||||
|
|
||||||
int newTreeToArrays(VoxelNode *currentNode);
|
int newTreeToArrays(VoxelNode *currentNode);
|
||||||
void cleanupRemovedVoxels();
|
void cleanupRemovedVoxels();
|
||||||
|
|
||||||
|
@ -224,6 +271,10 @@ private:
|
||||||
int _dataSourceID;
|
int _dataSourceID;
|
||||||
|
|
||||||
int _voxelServerCount;
|
int _voxelServerCount;
|
||||||
|
unsigned long _memoryUsageRAM;
|
||||||
|
unsigned long _memoryUsageVBO;
|
||||||
|
unsigned long _initialMemoryUsageGPU;
|
||||||
|
bool _hasMemoryUsageGPU;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
const bool BALLS_ON = false;
|
const bool BALLS_ON = false;
|
||||||
const bool USING_AVATAR_GRAVITY = true;
|
|
||||||
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
||||||
const float YAW_MAG = 500.0;
|
const float YAW_MAG = 500.0;
|
||||||
const float MY_HAND_HOLDING_PULL = 0.2;
|
const float MY_HAND_HOLDING_PULL = 0.2;
|
||||||
|
@ -289,7 +288,7 @@ void Avatar::follow(Avatar* leadingAvatar) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity) {
|
void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
|
|
||||||
glm::quat orientation = getOrientation();
|
glm::quat orientation = getOrientation();
|
||||||
glm::vec3 front = orientation * IDENTITY_FRONT;
|
glm::vec3 front = orientation * IDENTITY_FRONT;
|
||||||
|
@ -388,11 +387,22 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCamer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// head scale grows when avatar is looked at
|
||||||
|
if (Application::getInstance()->getLookatTargetAvatar() == this) {
|
||||||
|
const float BASE_MAX_SCALE = 3.0f;
|
||||||
|
const float GROW_SPEED = 0.1f;
|
||||||
|
_head.setScale(min(BASE_MAX_SCALE * glm::distance(_position, Application::getInstance()->getCamera()->getPosition()),
|
||||||
|
_head.getScale() + deltaTime * GROW_SPEED));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const float SHRINK_SPEED = 100.0f;
|
||||||
|
_head.setScale(max(_scale, _head.getScale() - deltaTime * SHRINK_SPEED));
|
||||||
|
}
|
||||||
|
|
||||||
_head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
|
_head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
|
||||||
_head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position);
|
_head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position);
|
||||||
_head.setScale(_scale);
|
|
||||||
_head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]));
|
_head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]));
|
||||||
_head.simulate(deltaTime, false, gyroCameraSensitivity);
|
_head.simulate(deltaTime, false);
|
||||||
_hand.simulate(deltaTime, false);
|
_hand.simulate(deltaTime, false);
|
||||||
|
|
||||||
// use speed and angular velocity to determine walking vs. standing
|
// use speed and angular velocity to determine walking vs. standing
|
||||||
|
@ -759,6 +769,7 @@ void Avatar::loadData(QSettings* settings) {
|
||||||
|
|
||||||
_voxels.setVoxelURL(settings->value("voxelURL").toUrl());
|
_voxels.setVoxelURL(settings->value("voxelURL").toUrl());
|
||||||
_head.getBlendFace().setModelURL(settings->value("faceModelURL").toUrl());
|
_head.getBlendFace().setModelURL(settings->value("faceModelURL").toUrl());
|
||||||
|
_head.setPupilDilation(settings->value("pupilDilation", 0.0f).toFloat());
|
||||||
|
|
||||||
_leanScale = loadSetting(settings, "leanScale", 0.05f);
|
_leanScale = loadSetting(settings, "leanScale", 0.05f);
|
||||||
|
|
||||||
|
@ -811,6 +822,7 @@ void Avatar::saveData(QSettings* set) {
|
||||||
|
|
||||||
set->setValue("voxelURL", _voxels.getVoxelURL());
|
set->setValue("voxelURL", _voxels.getVoxelURL());
|
||||||
set->setValue("faceModelURL", _head.getBlendFace().getModelURL());
|
set->setValue("faceModelURL", _head.getBlendFace().getModelURL());
|
||||||
|
set->setValue("pupilDilation", _head.getPupilDilation());
|
||||||
|
|
||||||
set->setValue("leanScale", _leanScale);
|
set->setValue("leanScale", _leanScale);
|
||||||
set->setValue("scale", _newScale);
|
set->setValue("scale", _newScale);
|
||||||
|
|
|
@ -135,7 +135,7 @@ public:
|
||||||
~Avatar();
|
~Avatar();
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity);
|
void simulate(float deltaTime, Transmitter* transmitter);
|
||||||
void follow(Avatar* leadingAvatar);
|
void follow(Avatar* leadingAvatar);
|
||||||
void render(bool lookingInMirror, bool renderAvatarBalls);
|
void render(bool lookingInMirror, bool renderAvatarBalls);
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ BlendFace::~BlendFace() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramObject BlendFace::_eyeProgram;
|
ProgramObject BlendFace::_eyeProgram;
|
||||||
GLuint BlendFace::_eyeTextureID;
|
DilatedTextureCache BlendFace::_eyeTextureCache("resources/images/eye.png", 50, 210);
|
||||||
|
|
||||||
void BlendFace::init() {
|
void BlendFace::init() {
|
||||||
if (!_eyeProgram.isLinked()) {
|
if (!_eyeProgram.isLinked()) {
|
||||||
|
@ -40,8 +40,6 @@ void BlendFace::init() {
|
||||||
_eyeProgram.bind();
|
_eyeProgram.bind();
|
||||||
_eyeProgram.setUniformValue("texture", 0);
|
_eyeProgram.setUniformValue("texture", 0);
|
||||||
_eyeProgram.release();
|
_eyeProgram.release();
|
||||||
|
|
||||||
_eyeTextureID = Application::getInstance()->getTextureCache()->getFileTextureID("resources/images/eye.png");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +90,9 @@ bool BlendFace::render(float alpha) {
|
||||||
// use texture coordinates only for the eye, for now
|
// use texture coordinates only for the eye, for now
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, _eyeTextureID);
|
_eyeTexture = _eyeTextureCache.getTexture(_owningHead->getPupilDilation());
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _eyeTexture->getID());
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
_eyeProgram.bind();
|
_eyeProgram.bind();
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
#include "renderer/FBXReader.h"
|
#include "renderer/FBXReader.h"
|
||||||
#include "renderer/ProgramObject.h"
|
#include "renderer/ProgramObject.h"
|
||||||
|
#include "renderer/TextureCache.h"
|
||||||
|
|
||||||
class QNetworkReply;
|
class QNetworkReply;
|
||||||
|
|
||||||
|
@ -62,8 +63,10 @@ private:
|
||||||
QVector<glm::vec3> _blendedVertices;
|
QVector<glm::vec3> _blendedVertices;
|
||||||
QVector<glm::vec3> _blendedNormals;
|
QVector<glm::vec3> _blendedNormals;
|
||||||
|
|
||||||
|
QSharedPointer<Texture> _eyeTexture;
|
||||||
|
|
||||||
static ProgramObject _eyeProgram;
|
static ProgramObject _eyeProgram;
|
||||||
static GLuint _eyeTextureID;
|
static DilatedTextureCache _eyeTextureCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__BlendFace__) */
|
#endif /* defined(__interface__BlendFace__) */
|
||||||
|
|
|
@ -29,7 +29,7 @@ const float EYEBALL_RADIUS = 0.017;
|
||||||
const float EYELID_RADIUS = 0.019;
|
const float EYELID_RADIUS = 0.019;
|
||||||
const float EYEBALL_COLOR[3] = { 0.9f, 0.9f, 0.8f };
|
const float EYEBALL_COLOR[3] = { 0.9f, 0.9f, 0.8f };
|
||||||
|
|
||||||
const float HAIR_SPRING_FORCE = 15.0f;
|
const float HAIR_SPRING_FORCE = 15.0f;
|
||||||
const float HAIR_TORQUE_FORCE = 0.2f;
|
const float HAIR_TORQUE_FORCE = 0.2f;
|
||||||
const float HAIR_GRAVITY_FORCE = 0.001f;
|
const float HAIR_GRAVITY_FORCE = 0.001f;
|
||||||
const float HAIR_DRAG = 10.0f;
|
const float HAIR_DRAG = 10.0f;
|
||||||
|
@ -46,7 +46,7 @@ const float IRIS_PROTRUSION = 0.0145f;
|
||||||
const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png";
|
const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png";
|
||||||
|
|
||||||
ProgramObject Head::_irisProgram;
|
ProgramObject Head::_irisProgram;
|
||||||
GLuint Head::_irisTextureID;
|
DilatedTextureCache Head::_irisTextureCache(IRIS_TEXTURE_FILENAME, 53, 127);
|
||||||
int Head::_eyePositionLocation;
|
int Head::_eyePositionLocation;
|
||||||
|
|
||||||
Head::Head(Avatar* owningAvatar) :
|
Head::Head(Avatar* owningAvatar) :
|
||||||
|
@ -71,6 +71,7 @@ Head::Head(Avatar* owningAvatar) :
|
||||||
_audioAttack(0.0f),
|
_audioAttack(0.0f),
|
||||||
_returnSpringScale(1.0f),
|
_returnSpringScale(1.0f),
|
||||||
_bodyRotation(0.0f, 0.0f, 0.0f),
|
_bodyRotation(0.0f, 0.0f, 0.0f),
|
||||||
|
_angularVelocity(0,0,0),
|
||||||
_renderLookatVectors(false),
|
_renderLookatVectors(false),
|
||||||
_mohawkInitialized(false),
|
_mohawkInitialized(false),
|
||||||
_saccade(0.0f, 0.0f, 0.0f),
|
_saccade(0.0f, 0.0f, 0.0f),
|
||||||
|
@ -102,13 +103,6 @@ void Head::init() {
|
||||||
|
|
||||||
_irisProgram.setUniformValue("texture", 0);
|
_irisProgram.setUniformValue("texture", 0);
|
||||||
_eyePositionLocation = _irisProgram.uniformLocation("eyePosition");
|
_eyePositionLocation = _irisProgram.uniformLocation("eyePosition");
|
||||||
|
|
||||||
_irisTextureID = Application::getInstance()->getTextureCache()->getFileTextureID(IRIS_TEXTURE_FILENAME);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, _irisTextureID);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
}
|
}
|
||||||
_blendFace.init();
|
_blendFace.init();
|
||||||
}
|
}
|
||||||
|
@ -139,7 +133,7 @@ void Head::resetHairPhysics() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Head::simulate(float deltaTime, bool isMine, float gyroCameraSensitivity) {
|
void Head::simulate(float deltaTime, bool isMine) {
|
||||||
|
|
||||||
// Update audio trailing average for rendering facial animations
|
// Update audio trailing average for rendering facial animations
|
||||||
Faceshift* faceshift = Application::getInstance()->getFaceshift();
|
Faceshift* faceshift = Application::getInstance()->getFaceshift();
|
||||||
|
@ -237,44 +231,6 @@ void Head::simulate(float deltaTime, bool isMine, float gyroCameraSensitivity) {
|
||||||
// based on the nature of the lookat position, determine if the eyes can look / are looking at it.
|
// based on the nature of the lookat position, determine if the eyes can look / are looking at it.
|
||||||
if (USING_PHYSICAL_MOHAWK) {
|
if (USING_PHYSICAL_MOHAWK) {
|
||||||
updateHairPhysics(deltaTime);
|
updateHairPhysics(deltaTime);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update camera pitch and yaw independently from motion of head (for gyro-based interface)
|
|
||||||
if (isMine && _cameraFollowsHead && (gyroCameraSensitivity > 0.f)) {
|
|
||||||
// If we are using gyros and using gyroLook, have the camera follow head but with a null region
|
|
||||||
// to create stable rendering view with small head movements.
|
|
||||||
const float CAMERA_FOLLOW_HEAD_RATE_START = 0.1f;
|
|
||||||
const float CAMERA_FOLLOW_HEAD_RATE_MAX = 1.0f;
|
|
||||||
const float CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE = 1.05f;
|
|
||||||
const float CAMERA_STOP_TOLERANCE_DEGREES = 0.5f;
|
|
||||||
const float PITCH_START_RANGE = 20.f;
|
|
||||||
const float YAW_START_RANGE = 10.f;
|
|
||||||
float pitchStartTolerance = PITCH_START_RANGE
|
|
||||||
* (1.f - gyroCameraSensitivity)
|
|
||||||
+ (2.f * CAMERA_STOP_TOLERANCE_DEGREES);
|
|
||||||
float yawStartTolerance = YAW_START_RANGE
|
|
||||||
* (1.f - gyroCameraSensitivity)
|
|
||||||
+ (2.f * CAMERA_STOP_TOLERANCE_DEGREES);
|
|
||||||
|
|
||||||
float cameraHeadAngleDifference = glm::length(glm::vec2(_pitch - _cameraPitch, _yaw - _cameraYaw));
|
|
||||||
if (_isCameraMoving) {
|
|
||||||
_cameraFollowHeadRate = glm::clamp(_cameraFollowHeadRate * CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE,
|
|
||||||
0.f,
|
|
||||||
CAMERA_FOLLOW_HEAD_RATE_MAX);
|
|
||||||
|
|
||||||
_cameraPitch += (_pitch - _cameraPitch) * _cameraFollowHeadRate;
|
|
||||||
_cameraYaw += (_yaw - _cameraYaw) * _cameraFollowHeadRate;
|
|
||||||
if (cameraHeadAngleDifference < CAMERA_STOP_TOLERANCE_DEGREES) {
|
|
||||||
_isCameraMoving = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((fabs(_pitch - _cameraPitch) > pitchStartTolerance) ||
|
|
||||||
(fabs(_yaw - _cameraYaw) > yawStartTolerance)) {
|
|
||||||
_isCameraMoving = true;
|
|
||||||
_cameraFollowHeadRate = CAMERA_FOLLOW_HEAD_RATE_START;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,7 +623,12 @@ void Head::renderEyeBalls() {
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
_irisProgram.bind();
|
_irisProgram.bind();
|
||||||
glBindTexture(GL_TEXTURE_2D, _irisTextureID);
|
|
||||||
|
_irisTexture = _irisTextureCache.getTexture(_pupilDilation);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _irisTexture->getID());
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
// render left iris
|
// render left iris
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "PerlinFace.h"
|
#include "PerlinFace.h"
|
||||||
#include "world.h"
|
#include "world.h"
|
||||||
#include "devices/SerialInterface.h"
|
#include "devices/SerialInterface.h"
|
||||||
|
#include "renderer/TextureCache.h"
|
||||||
|
|
||||||
enum eyeContactTargets {
|
enum eyeContactTargets {
|
||||||
LEFT_EYE,
|
LEFT_EYE,
|
||||||
|
@ -43,7 +44,7 @@ public:
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void reset();
|
void reset();
|
||||||
void simulate(float deltaTime, bool isMine, float gyroCameraSensitivity);
|
void simulate(float deltaTime, bool isMine);
|
||||||
void render(float alpha, bool isMine);
|
void render(float alpha, bool isMine);
|
||||||
void renderMohawk();
|
void renderMohawk();
|
||||||
|
|
||||||
|
@ -63,6 +64,8 @@ public:
|
||||||
|
|
||||||
glm::quat getOrientation() const;
|
glm::quat getOrientation() const;
|
||||||
glm::quat getCameraOrientation () const;
|
glm::quat getCameraOrientation () const;
|
||||||
|
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||||
|
void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; }
|
||||||
|
|
||||||
float getScale() const { return _scale; }
|
float getScale() const { return _scale; }
|
||||||
glm::vec3 getPosition() const { return _position; }
|
glm::vec3 getPosition() const { return _position; }
|
||||||
|
@ -115,6 +118,7 @@ private:
|
||||||
float _audioAttack;
|
float _audioAttack;
|
||||||
float _returnSpringScale; //strength of return springs
|
float _returnSpringScale; //strength of return springs
|
||||||
glm::vec3 _bodyRotation;
|
glm::vec3 _bodyRotation;
|
||||||
|
glm::vec3 _angularVelocity;
|
||||||
bool _renderLookatVectors;
|
bool _renderLookatVectors;
|
||||||
BendyLine _hairTuft[NUM_HAIR_TUFTS];
|
BendyLine _hairTuft[NUM_HAIR_TUFTS];
|
||||||
bool _mohawkInitialized;
|
bool _mohawkInitialized;
|
||||||
|
@ -135,8 +139,10 @@ private:
|
||||||
PerlinFace _perlinFace;
|
PerlinFace _perlinFace;
|
||||||
BlendFace _blendFace;
|
BlendFace _blendFace;
|
||||||
|
|
||||||
|
QSharedPointer<Texture> _irisTexture;
|
||||||
|
|
||||||
static ProgramObject _irisProgram;
|
static ProgramObject _irisProgram;
|
||||||
static GLuint _irisTextureID;
|
static DilatedTextureCache _irisTextureCache;
|
||||||
static int _eyePositionLocation;
|
static int _eyePositionLocation;
|
||||||
|
|
||||||
// private methods
|
// private methods
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
const bool USING_AVATAR_GRAVITY = true;
|
|
||||||
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
||||||
const float YAW_MAG = 500.0;
|
const float YAW_MAG = 500.0;
|
||||||
const float COLLISION_RADIUS_SCALAR = 1.2; // pertains to avatar-to-avatar collisions
|
const float COLLISION_RADIUS_SCALAR = 1.2; // pertains to avatar-to-avatar collisions
|
||||||
|
@ -51,7 +50,9 @@ MyAvatar::MyAvatar(Node* owningNode) :
|
||||||
_lastCollisionPosition(0, 0, 0),
|
_lastCollisionPosition(0, 0, 0),
|
||||||
_speedBrakes(false),
|
_speedBrakes(false),
|
||||||
_isThrustOn(false),
|
_isThrustOn(false),
|
||||||
_thrustMultiplier(1.0f)
|
_thrustMultiplier(1.0f),
|
||||||
|
_moveTarget(0,0,0),
|
||||||
|
_moveTargetStepCounter(0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||||
_driveKeys[i] = false;
|
_driveKeys[i] = false;
|
||||||
|
@ -65,7 +66,12 @@ void MyAvatar::reset() {
|
||||||
_hand.reset();
|
_hand.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity) {
|
void MyAvatar::setMoveTarget(const glm::vec3 moveTarget) {
|
||||||
|
_moveTarget = moveTarget;
|
||||||
|
_moveTargetStepCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
|
|
||||||
glm::quat orientation = getOrientation();
|
glm::quat orientation = getOrientation();
|
||||||
glm::vec3 front = orientation * IDENTITY_FRONT;
|
glm::vec3 front = orientation * IDENTITY_FRONT;
|
||||||
|
@ -160,16 +166,16 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam
|
||||||
_avatarTouch.simulate(deltaTime);
|
_avatarTouch.simulate(deltaTime);
|
||||||
|
|
||||||
// apply gravity
|
// apply gravity
|
||||||
if (USING_AVATAR_GRAVITY) {
|
// For gravity, always move the avatar by the amount driven by gravity, so that the collision
|
||||||
// For gravity, always move the avatar by the amount driven by gravity, so that the collision
|
// routines will detect it and collide every frame when pulled by gravity to a surface
|
||||||
// routines will detect it and collide every frame when pulled by gravity to a surface
|
const float MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY = 0.02f;
|
||||||
const float MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY = 0.02f;
|
if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) {
|
||||||
if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) {
|
_velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime);
|
||||||
_velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only collide if we are not moving to a target
|
||||||
|
if (_isCollisionsOn && (glm::length(_moveTarget) < EPSILON)) {
|
||||||
|
|
||||||
if (_isCollisionsOn) {
|
|
||||||
Camera* myCamera = Application::getInstance()->getCamera();
|
Camera* myCamera = Application::getInstance()->getCamera();
|
||||||
|
|
||||||
if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) {
|
if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) {
|
||||||
|
@ -211,23 +217,32 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam
|
||||||
const float STATIC_FRICTION_STRENGTH = _scale * 20.f;
|
const float STATIC_FRICTION_STRENGTH = _scale * 20.f;
|
||||||
applyStaticFriction(deltaTime, _velocity, MAX_STATIC_FRICTION_VELOCITY, STATIC_FRICTION_STRENGTH);
|
applyStaticFriction(deltaTime, _velocity, MAX_STATIC_FRICTION_VELOCITY, STATIC_FRICTION_STRENGTH);
|
||||||
|
|
||||||
|
// Damp avatar velocity
|
||||||
const float LINEAR_DAMPING_STRENGTH = 0.5f;
|
const float LINEAR_DAMPING_STRENGTH = 0.5f;
|
||||||
const float SPEED_BRAKE_POWER = _scale * 10.0f;
|
const float SPEED_BRAKE_POWER = _scale * 10.0f;
|
||||||
// Note: PER changed squared damping strength to zero
|
const float SQUARED_DAMPING_STRENGTH = 0.007f;
|
||||||
const float SQUARED_DAMPING_STRENGTH = 0.0f;
|
|
||||||
|
float linearDamping = LINEAR_DAMPING_STRENGTH;
|
||||||
|
const float AVATAR_DAMPING_FACTOR = 120.f;
|
||||||
|
if (_distanceToNearestAvatar < _scale * PERIPERSONAL_RADIUS) {
|
||||||
|
linearDamping *= 1.f + AVATAR_DAMPING_FACTOR * (PERIPERSONAL_RADIUS - _distanceToNearestAvatar);
|
||||||
|
}
|
||||||
if (_speedBrakes) {
|
if (_speedBrakes) {
|
||||||
applyDamping(deltaTime, _velocity, LINEAR_DAMPING_STRENGTH * SPEED_BRAKE_POWER, SQUARED_DAMPING_STRENGTH * SPEED_BRAKE_POWER);
|
applyDamping(deltaTime, _velocity, linearDamping * SPEED_BRAKE_POWER, SQUARED_DAMPING_STRENGTH * SPEED_BRAKE_POWER);
|
||||||
} else {
|
} else {
|
||||||
applyDamping(deltaTime, _velocity, LINEAR_DAMPING_STRENGTH, SQUARED_DAMPING_STRENGTH);
|
applyDamping(deltaTime, _velocity, linearDamping, SQUARED_DAMPING_STRENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pitch and roll the body as a function of forward speed and turning delta
|
// pitch and roll the body as a function of forward speed and turning delta
|
||||||
const float BODY_PITCH_WHILE_WALKING = -20.0;
|
const float HIGH_VELOCITY = 10.f;
|
||||||
const float BODY_ROLL_WHILE_TURNING = 0.2;
|
if (glm::length(_velocity) < HIGH_VELOCITY) {
|
||||||
float forwardComponentOfVelocity = glm::dot(getBodyFrontDirection(), _velocity);
|
const float BODY_PITCH_WHILE_WALKING = -20.0;
|
||||||
orientation = orientation * glm::quat(glm::radians(glm::vec3(
|
const float BODY_ROLL_WHILE_TURNING = 0.2;
|
||||||
BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity, 0.0f,
|
float forwardComponentOfVelocity = glm::dot(getBodyFrontDirection(), _velocity);
|
||||||
BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta)));
|
orientation = orientation * glm::quat(glm::radians(glm::vec3(
|
||||||
|
BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity, 0.0f,
|
||||||
|
BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta)));
|
||||||
|
}
|
||||||
|
|
||||||
// these forces keep the body upright...
|
// these forces keep the body upright...
|
||||||
const float BODY_UPRIGHT_FORCE = _scale * 10.0;
|
const float BODY_UPRIGHT_FORCE = _scale * 10.0;
|
||||||
|
@ -303,7 +318,7 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam
|
||||||
_head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position);
|
_head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position);
|
||||||
_head.setScale(_scale);
|
_head.setScale(_scale);
|
||||||
_head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]));
|
_head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]));
|
||||||
_head.simulate(deltaTime, true, gyroCameraSensitivity);
|
_head.simulate(deltaTime, true);
|
||||||
_hand.simulate(deltaTime, true);
|
_hand.simulate(deltaTime, true);
|
||||||
|
|
||||||
const float WALKING_SPEED_THRESHOLD = 0.2f;
|
const float WALKING_SPEED_THRESHOLD = 0.2f;
|
||||||
|
@ -318,7 +333,21 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam
|
||||||
const float MOVING_SPEED_THRESHOLD = 0.01f;
|
const float MOVING_SPEED_THRESHOLD = 0.01f;
|
||||||
_moving = _speed > MOVING_SPEED_THRESHOLD;
|
_moving = _speed > MOVING_SPEED_THRESHOLD;
|
||||||
|
|
||||||
// update position by velocity, and subtract the change added earlier for gravity
|
// If a move target is set, update position explicitly
|
||||||
|
const float MOVE_FINISHED_TOLERANCE = 0.1f;
|
||||||
|
const float MOVE_SPEED_FACTOR = 2.f;
|
||||||
|
const int MOVE_TARGET_MAX_STEPS = 250;
|
||||||
|
if ((glm::length(_moveTarget) > EPSILON) && (_moveTargetStepCounter < MOVE_TARGET_MAX_STEPS)) {
|
||||||
|
if (glm::length(_position - _moveTarget) > MOVE_FINISHED_TOLERANCE) {
|
||||||
|
_position += (_moveTarget - _position) * (deltaTime * MOVE_SPEED_FACTOR);
|
||||||
|
_moveTargetStepCounter++;
|
||||||
|
} else {
|
||||||
|
// Move completed
|
||||||
|
_moveTarget = glm::vec3(0,0,0);
|
||||||
|
_moveTargetStepCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_position += _velocity * deltaTime;
|
_position += _velocity * deltaTime;
|
||||||
|
|
||||||
// Zero thrust out now that we've added it to velocity in this frame
|
// Zero thrust out now that we've added it to velocity in this frame
|
||||||
|
@ -337,7 +366,13 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool gyroLook,
|
||||||
if (faceshift->isActive()) {
|
if (faceshift->isActive()) {
|
||||||
estimatedPosition = faceshift->getHeadTranslation();
|
estimatedPosition = faceshift->getHeadTranslation();
|
||||||
estimatedRotation = safeEulerAngles(faceshift->getHeadRotation());
|
estimatedRotation = safeEulerAngles(faceshift->getHeadRotation());
|
||||||
|
// Rotate the body if the head is turned quickly
|
||||||
|
glm::vec3 headAngularVelocity = faceshift->getHeadAngularVelocity();
|
||||||
|
const float FACESHIFT_YAW_VIEW_SENSITIVITY = 20.f;
|
||||||
|
const float FACESHIFT_MIN_YAW_VELOCITY = 1.0f;
|
||||||
|
if (fabs(headAngularVelocity.y) > FACESHIFT_MIN_YAW_VELOCITY) {
|
||||||
|
_bodyYawDelta += headAngularVelocity.y * FACESHIFT_YAW_VIEW_SENSITIVITY;
|
||||||
|
}
|
||||||
} else if (gyros->isActive()) {
|
} else if (gyros->isActive()) {
|
||||||
estimatedRotation = gyros->getEstimatedRotation();
|
estimatedRotation = gyros->getEstimatedRotation();
|
||||||
|
|
||||||
|
@ -639,15 +674,21 @@ void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) {
|
||||||
|
|
||||||
// If thrust keys are being held down, slowly increase thrust to allow reaching great speeds
|
// If thrust keys are being held down, slowly increase thrust to allow reaching great speeds
|
||||||
if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) {
|
if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) {
|
||||||
const float THRUST_INCREASE_RATE = 1.0;
|
const float THRUST_INCREASE_RATE = 1.05;
|
||||||
_thrustMultiplier *= 1.f + deltaTime * THRUST_INCREASE_RATE;
|
const float MAX_THRUST_MULTIPLIER = 75.0;
|
||||||
|
//printf("m = %.3f\n", _thrustMultiplier);
|
||||||
|
if (_thrustMultiplier < MAX_THRUST_MULTIPLIER) {
|
||||||
|
_thrustMultiplier *= 1.f + deltaTime * THRUST_INCREASE_RATE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_thrustMultiplier = 1.f;
|
_thrustMultiplier = 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add one time jumping force if requested
|
// Add one time jumping force if requested
|
||||||
if (_shouldJump) {
|
if (_shouldJump) {
|
||||||
_thrust += _scale * THRUST_JUMP * up;
|
if (glm::length(_gravity) > EPSILON) {
|
||||||
|
_thrust += _scale * THRUST_JUMP * up;
|
||||||
|
}
|
||||||
_shouldJump = false;
|
_shouldJump = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ public:
|
||||||
MyAvatar(Node* owningNode = NULL);
|
MyAvatar(Node* owningNode = NULL);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity);
|
void simulate(float deltaTime, Transmitter* transmitter);
|
||||||
void updateFromGyrosAndOrWebcam(bool gyroLook, float pitchFromTouch);
|
void updateFromGyrosAndOrWebcam(bool gyroLook, float pitchFromTouch);
|
||||||
void render(bool lookingInMirror, bool renderAvatarBalls);
|
void render(bool lookingInMirror, bool renderAvatarBalls);
|
||||||
void renderScreenTint(ScreenTintLayer layer, Camera& whichCamera);
|
void renderScreenTint(ScreenTintLayer layer, Camera& whichCamera);
|
||||||
|
@ -31,6 +31,7 @@ public:
|
||||||
void setOrientation(const glm::quat& orientation);
|
void setOrientation(const glm::quat& orientation);
|
||||||
void setNewScale(const float scale);
|
void setNewScale(const float scale);
|
||||||
void setWantCollisionsOn(bool wantCollisionsOn) { _isCollisionsOn = wantCollisionsOn; }
|
void setWantCollisionsOn(bool wantCollisionsOn) { _isCollisionsOn = wantCollisionsOn; }
|
||||||
|
void setMoveTarget(const glm::vec3 moveTarget);
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
float getNewScale() const { return _newScale; }
|
float getNewScale() const { return _newScale; }
|
||||||
|
@ -73,6 +74,8 @@ public:
|
||||||
bool _isThrustOn;
|
bool _isThrustOn;
|
||||||
float _thrustMultiplier;
|
float _thrustMultiplier;
|
||||||
float _collisionRadius;
|
float _collisionRadius;
|
||||||
|
glm::vec3 _moveTarget;
|
||||||
|
int _moveTargetStepCounter;
|
||||||
|
|
||||||
// private methods
|
// private methods
|
||||||
float getBallRenderAlpha(int ball, bool lookingInMirror) const;
|
float getBallRenderAlpha(int ball, bool lookingInMirror) const;
|
||||||
|
|
|
@ -248,7 +248,11 @@ void PerlinFace::render() {
|
||||||
|
|
||||||
|
|
||||||
Head::_irisProgram.bind();
|
Head::_irisProgram.bind();
|
||||||
glBindTexture(GL_TEXTURE_2D, Head::_irisTextureID);
|
_owningHead->_irisTexture = Head::_irisTextureCache.getTexture(_owningHead->_pupilDilation);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _owningHead->_irisTexture->getID());
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
orientation = _owningHead->getOrientation();
|
orientation = _owningHead->getOrientation();
|
||||||
|
|
|
@ -142,8 +142,20 @@ void Faceshift::receive(const QByteArray& buffer) {
|
||||||
case fsMsg::MSG_OUT_TRACKING_STATE: {
|
case fsMsg::MSG_OUT_TRACKING_STATE: {
|
||||||
const fsTrackingData& data = static_cast<fsMsgTrackingState*>(msg.get())->tracking_data();
|
const fsTrackingData& data = static_cast<fsMsgTrackingState*>(msg.get())->tracking_data();
|
||||||
if ((_tracking = data.m_trackingSuccessful)) {
|
if ((_tracking = data.m_trackingSuccessful)) {
|
||||||
_headRotation = glm::quat(data.m_headRotation.w, -data.m_headRotation.x,
|
glm::quat newRotation = glm::quat(data.m_headRotation.w, -data.m_headRotation.x,
|
||||||
data.m_headRotation.y, -data.m_headRotation.z);
|
data.m_headRotation.y, -data.m_headRotation.z);
|
||||||
|
// Compute angular velocity of the head
|
||||||
|
glm::quat r = newRotation * glm::inverse(_headRotation);
|
||||||
|
float theta = 2 * acos(r.w);
|
||||||
|
if (theta > EPSILON) {
|
||||||
|
float rMag = glm::length(glm::vec3(r.x, r.y, r.z));
|
||||||
|
float AVERAGE_FACESHIFT_FRAME_TIME = 0.033f;
|
||||||
|
_headAngularVelocity = theta / AVERAGE_FACESHIFT_FRAME_TIME * glm::vec3(r.x, r.y, r.z) / rMag;
|
||||||
|
} else {
|
||||||
|
_headAngularVelocity = glm::vec3(0,0,0);
|
||||||
|
}
|
||||||
|
_headRotation = newRotation;
|
||||||
|
|
||||||
const float TRANSLATION_SCALE = 0.02f;
|
const float TRANSLATION_SCALE = 0.02f;
|
||||||
_headTranslation = glm::vec3(data.m_headTranslation.x, data.m_headTranslation.y,
|
_headTranslation = glm::vec3(data.m_headTranslation.x, data.m_headTranslation.y,
|
||||||
-data.m_headTranslation.z) * TRANSLATION_SCALE;
|
-data.m_headTranslation.z) * TRANSLATION_SCALE;
|
||||||
|
|
|
@ -30,6 +30,7 @@ public:
|
||||||
bool isActive() const;
|
bool isActive() const;
|
||||||
|
|
||||||
const glm::quat& getHeadRotation() const { return _headRotation; }
|
const glm::quat& getHeadRotation() const { return _headRotation; }
|
||||||
|
const glm::vec3& getHeadAngularVelocity() const { return _headAngularVelocity; }
|
||||||
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
||||||
|
|
||||||
float getEyeGazeLeftPitch() const { return _eyeGazeLeftPitch; }
|
float getEyeGazeLeftPitch() const { return _eyeGazeLeftPitch; }
|
||||||
|
@ -88,6 +89,7 @@ private:
|
||||||
uint64_t _lastTrackingStateReceived;
|
uint64_t _lastTrackingStateReceived;
|
||||||
|
|
||||||
glm::quat _headRotation;
|
glm::quat _headRotation;
|
||||||
|
glm::vec3 _headAngularVelocity;
|
||||||
glm::vec3 _headTranslation;
|
glm::vec3 _headTranslation;
|
||||||
|
|
||||||
float _eyeGazeLeftPitch;
|
float _eyeGazeLeftPitch;
|
||||||
|
|
|
@ -154,3 +154,44 @@ QOpenGLFramebufferObject* TextureCache::createFramebufferObject() {
|
||||||
|
|
||||||
return fbo;
|
return fbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture::Texture() {
|
||||||
|
glGenTextures(1, &_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture::~Texture() {
|
||||||
|
glDeleteTextures(1, &_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
DilatedTextureCache::DilatedTextureCache(const QString& filename, int innerRadius, int outerRadius) :
|
||||||
|
_innerRadius(innerRadius),
|
||||||
|
_outerRadius(outerRadius)
|
||||||
|
{
|
||||||
|
switchToResourcesParentIfRequired();
|
||||||
|
_image = QImage(filename).convertToFormat(QImage::Format_ARGB32);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<Texture> DilatedTextureCache::getTexture(float dilation) {
|
||||||
|
QSharedPointer<Texture> texture = _textures.value(dilation);
|
||||||
|
if (texture.isNull()) {
|
||||||
|
texture = QSharedPointer<Texture>(new Texture());
|
||||||
|
|
||||||
|
QImage dilatedImage = _image;
|
||||||
|
QPainter painter;
|
||||||
|
painter.begin(&dilatedImage);
|
||||||
|
QPainterPath path;
|
||||||
|
qreal radius = glm::mix(_innerRadius, _outerRadius, dilation);
|
||||||
|
path.addEllipse(QPointF(_image.width() / 2.0, _image.height() / 2.0), radius, radius);
|
||||||
|
painter.fillPath(path, Qt::black);
|
||||||
|
painter.end();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture->getID());
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 1,
|
||||||
|
GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits());
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
_textures.insert(dilation, texture);
|
||||||
|
}
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,11 @@
|
||||||
#define __interface__TextureCache__
|
#define __interface__TextureCache__
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QMap>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QWeakPointer>
|
||||||
|
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
|
@ -62,4 +66,36 @@ private:
|
||||||
QOpenGLFramebufferObject* _tertiaryFramebufferObject;
|
QOpenGLFramebufferObject* _tertiaryFramebufferObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A simple object wrapper for an OpenGL texture.
|
||||||
|
class Texture {
|
||||||
|
public:
|
||||||
|
|
||||||
|
Texture();
|
||||||
|
~Texture();
|
||||||
|
|
||||||
|
GLuint getID() const { return _id; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
GLuint _id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Caches textures according to pupillary dilation.
|
||||||
|
class DilatedTextureCache {
|
||||||
|
public:
|
||||||
|
|
||||||
|
DilatedTextureCache(const QString& filename, int innerRadius, int outerRadius);
|
||||||
|
|
||||||
|
/// Returns a pointer to a texture with the requested amount of dilation.
|
||||||
|
QSharedPointer<Texture> getTexture(float dilation);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QImage _image;
|
||||||
|
int _innerRadius;
|
||||||
|
int _outerRadius;
|
||||||
|
|
||||||
|
QMap<float, QWeakPointer<Texture> > _textures;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__TextureCache__) */
|
#endif /* defined(__interface__TextureCache__) */
|
||||||
|
|
69
interface/src/renderer/VoxelShader.cpp
Normal file
69
interface/src/renderer/VoxelShader.cpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
//
|
||||||
|
// VoxelShader.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 9/22/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
|
||||||
|
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
|
||||||
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
|
#include <QOpenGLFramebufferObject>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "VoxelShader.h"
|
||||||
|
#include "ProgramObject.h"
|
||||||
|
#include "RenderUtil.h"
|
||||||
|
|
||||||
|
VoxelShader::VoxelShader()
|
||||||
|
: _initialized(false)
|
||||||
|
{
|
||||||
|
_program = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VoxelShader::~VoxelShader() {
|
||||||
|
if (_initialized) {
|
||||||
|
delete _program;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgramObject* VoxelShader::createGeometryShaderProgram(const QString& name) {
|
||||||
|
ProgramObject* program = new ProgramObject();
|
||||||
|
program->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/passthrough.vert" );
|
||||||
|
program->addShaderFromSourceFile(QGLShader::Geometry, "resources/shaders/" + name + ".geom" );
|
||||||
|
program->setGeometryInputType(GL_POINTS);
|
||||||
|
program->setGeometryOutputType(GL_TRIANGLE_STRIP);
|
||||||
|
const int VERTICES_PER_FACE = 4;
|
||||||
|
const int FACES_PER_VOXEL = 6;
|
||||||
|
const int VERTICES_PER_VOXEL = VERTICES_PER_FACE * FACES_PER_VOXEL;
|
||||||
|
program->setGeometryOutputVertexCount(VERTICES_PER_VOXEL);
|
||||||
|
program->link();
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelShader::init() {
|
||||||
|
if (_initialized) {
|
||||||
|
qDebug("[ERROR] TestProgram is already initialized.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switchToResourcesParentIfRequired();
|
||||||
|
_program = createGeometryShaderProgram("voxel");
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelShader::begin() {
|
||||||
|
_program->bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelShader::end() {
|
||||||
|
_program->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
int VoxelShader::attributeLocation(const char * name) const {
|
||||||
|
if (_program) {
|
||||||
|
return _program->attributeLocation(name);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
46
interface/src/renderer/VoxelShader.h
Normal file
46
interface/src/renderer/VoxelShader.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
//
|
||||||
|
// VoxelShader.h
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 9/23/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __interface__VoxelShader__
|
||||||
|
#define __interface__VoxelShader__
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class ProgramObject;
|
||||||
|
|
||||||
|
/// A generic full screen glow effect.
|
||||||
|
class VoxelShader : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
VoxelShader();
|
||||||
|
~VoxelShader();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/// Starts using the voxel geometry shader effect.
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
/// Stops using the voxel geometry shader effect.
|
||||||
|
void end();
|
||||||
|
|
||||||
|
/// Gets access to attributes from the shader program
|
||||||
|
int attributeLocation(const char * name) const;
|
||||||
|
|
||||||
|
static ProgramObject* createGeometryShaderProgram(const QString& name);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool _initialized;
|
||||||
|
|
||||||
|
ProgramObject* _program;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__interface__VoxelShader__) */
|
|
@ -211,6 +211,9 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
||||||
destinationBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float);
|
destinationBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pupil dilation
|
||||||
|
destinationBuffer += packFloatToByte(destinationBuffer, _headData->_pupilDilation, 1.0f);
|
||||||
|
|
||||||
// leap hand data
|
// leap hand data
|
||||||
destinationBuffer += _handData->encodeRemoteData(destinationBuffer);
|
destinationBuffer += _handData->encodeRemoteData(destinationBuffer);
|
||||||
|
|
||||||
|
@ -345,7 +348,10 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
_headData->_blendshapeCoefficients.size() * sizeof(float));
|
_headData->_blendshapeCoefficients.size() * sizeof(float));
|
||||||
sourceBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float);
|
sourceBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pupil dilation
|
||||||
|
sourceBuffer += unpackFloatFromByte(sourceBuffer, _headData->_pupilDilation, 1.0f);
|
||||||
|
|
||||||
// leap hand data
|
// leap hand data
|
||||||
if (sourceBuffer - startPosition < numBytes) {
|
if (sourceBuffer - startPosition < numBytes) {
|
||||||
// check passed, bytes match
|
// check passed, bytes match
|
||||||
|
|
|
@ -46,6 +46,9 @@ public:
|
||||||
|
|
||||||
const std::vector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
const std::vector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||||
|
|
||||||
|
float getPupilDilation() const { return _pupilDilation; }
|
||||||
|
void setPupilDilation(float pupilDilation) { _pupilDilation = pupilDilation; }
|
||||||
|
|
||||||
void addYaw(float yaw);
|
void addYaw(float yaw);
|
||||||
void addPitch(float pitch);
|
void addPitch(float pitch);
|
||||||
void addRoll(float roll);
|
void addRoll(float roll);
|
||||||
|
@ -70,6 +73,7 @@ protected:
|
||||||
float _averageLoudness;
|
float _averageLoudness;
|
||||||
float _browAudioLift;
|
float _browAudioLift;
|
||||||
std::vector<float> _blendshapeCoefficients;
|
std::vector<float> _blendshapeCoefficients;
|
||||||
|
float _pupilDilation;
|
||||||
AvatarData* _owningAvatar;
|
AvatarData* _owningAvatar;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -109,6 +109,7 @@ void NodeList::setDomainHostname(const QString& domainHostname) {
|
||||||
|
|
||||||
// reset our _domainIP to the null address so that a lookup happens on next check in
|
// reset our _domainIP to the null address so that a lookup happens on next check in
|
||||||
_domainIP.clear();
|
_domainIP.clear();
|
||||||
|
notifyDomainChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
|
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
|
||||||
|
@ -586,6 +587,7 @@ void NodeList::loadData(QSettings *settings) {
|
||||||
|
|
||||||
if (domainServerHostname.size() > 0) {
|
if (domainServerHostname.size() > 0) {
|
||||||
_domainHostname = domainServerHostname;
|
_domainHostname = domainServerHostname;
|
||||||
|
notifyDomainChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
|
@ -679,6 +681,21 @@ void NodeListIterator::skipDeadAndStopIncrement() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeList::addDomainListener(DomainChangeListener* listener) {
|
||||||
|
_domainListeners.push_back(listener);
|
||||||
|
QString domain = _domainHostname.isEmpty() ? _domainIP.toString() : _domainHostname;
|
||||||
|
listener->domainChanged(domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeList::removeDomainListener(DomainChangeListener* listener) {
|
||||||
|
for (int i = 0; i < _domainListeners.size(); i++) {
|
||||||
|
if (_domainListeners[i] == listener) {
|
||||||
|
_domainListeners.erase(_domainListeners.begin() + i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NodeList::addHook(NodeListHook* hook) {
|
void NodeList::addHook(NodeListHook* hook) {
|
||||||
_hooks.push_back(hook);
|
_hooks.push_back(hook);
|
||||||
}
|
}
|
||||||
|
@ -705,3 +722,9 @@ void NodeList::notifyHooksOfKilledNode(Node* node) {
|
||||||
_hooks[i]->nodeKilled(node);
|
_hooks[i]->nodeKilled(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeList::notifyDomainChanged() {
|
||||||
|
for (int i = 0; i < _domainListeners.size(); i++) {
|
||||||
|
_domainListeners[i]->domainChanged(_domainHostname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -56,6 +56,11 @@ public:
|
||||||
virtual void nodeKilled(Node* node) = 0;
|
virtual void nodeKilled(Node* node) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DomainChangeListener {
|
||||||
|
public:
|
||||||
|
virtual void domainChanged(QString domain) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class NodeList {
|
class NodeList {
|
||||||
public:
|
public:
|
||||||
static NodeList* createInstance(char ownerType, unsigned short int socketListenPort = 0);
|
static NodeList* createInstance(char ownerType, unsigned short int socketListenPort = 0);
|
||||||
|
@ -135,6 +140,9 @@ public:
|
||||||
void notifyHooksOfAddedNode(Node* node);
|
void notifyHooksOfAddedNode(Node* node);
|
||||||
void notifyHooksOfKilledNode(Node* node);
|
void notifyHooksOfKilledNode(Node* node);
|
||||||
|
|
||||||
|
void addDomainListener(DomainChangeListener* listener);
|
||||||
|
void removeDomainListener(DomainChangeListener* listener);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static NodeList* _sharedInstance;
|
static NodeList* _sharedInstance;
|
||||||
|
|
||||||
|
@ -166,6 +174,11 @@ private:
|
||||||
void timePingReply(sockaddr *nodeAddress, unsigned char *packetData);
|
void timePingReply(sockaddr *nodeAddress, unsigned char *packetData);
|
||||||
|
|
||||||
std::vector<NodeListHook*> _hooks;
|
std::vector<NodeListHook*> _hooks;
|
||||||
|
std::vector<DomainChangeListener*> _domainListeners;
|
||||||
|
|
||||||
|
void resetDomainData(char domainField[], const char* domainData);
|
||||||
|
void notifyDomainChanged();
|
||||||
|
void domainLookup();
|
||||||
};
|
};
|
||||||
|
|
||||||
class NodeListIterator : public std::iterator<std::input_iterator_tag, Node> {
|
class NodeListIterator : public std::iterator<std::input_iterator_tag, Node> {
|
||||||
|
|
|
@ -20,7 +20,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case PACKET_TYPE_HEAD_DATA:
|
case PACKET_TYPE_HEAD_DATA:
|
||||||
return 7;
|
return 8;
|
||||||
|
|
||||||
case PACKET_TYPE_AVATAR_URLS:
|
case PACKET_TYPE_AVATAR_URLS:
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -32,12 +32,18 @@ const float VOXEL_SIZE_SCALE = TREE_SCALE * 400.0f;
|
||||||
const int NUMBER_OF_CHILDREN = 8;
|
const int NUMBER_OF_CHILDREN = 8;
|
||||||
const int MAX_VOXEL_PACKET_SIZE = 1492;
|
const int MAX_VOXEL_PACKET_SIZE = 1492;
|
||||||
const int MAX_TREE_SLICE_BYTES = 26;
|
const int MAX_TREE_SLICE_BYTES = 26;
|
||||||
const int MAX_VOXELS_PER_SYSTEM = 200000;
|
const int DEFAULT_MAX_VOXELS_PER_SYSTEM = 200000;
|
||||||
const int VERTICES_PER_VOXEL = 24;
|
const int VERTICES_PER_VOXEL = 24; // 6 sides * 4 corners per side
|
||||||
const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; // xyz for each VERTICE_PER_VOXEL
|
||||||
const int INDICES_PER_VOXEL = 3 * 12;
|
const int INDICES_PER_VOXEL = 3 * 12; // 6 sides * 2 triangles per size * 3 vertices per triangle
|
||||||
const int COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * VERTICES_PER_VOXEL;
|
const int COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * VERTICES_PER_VOXEL;
|
||||||
|
|
||||||
|
const int VERTICES_PER_FACE = 4; // 6 sides * 4 corners per side
|
||||||
|
const int INDICES_PER_FACE = 3 * 2; // 1 side * 2 triangles per size * 3 vertices per triangle
|
||||||
|
const int GLOBAL_NORMALS_VERTICES_PER_VOXEL = 8; // no need for 3 copies because they don't include normal
|
||||||
|
const int GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL = 3 * GLOBAL_NORMALS_VERTICES_PER_VOXEL;
|
||||||
|
const int GLOBAL_NORMALS_COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * GLOBAL_NORMALS_VERTICES_PER_VOXEL;
|
||||||
|
|
||||||
typedef unsigned long int glBufferIndex;
|
typedef unsigned long int glBufferIndex;
|
||||||
const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;
|
const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ public:
|
||||||
void printDebugDetails(const char* label) const;
|
void printDebugDetails(const char* label) const;
|
||||||
bool isDirty() const { return _isDirty; }
|
bool isDirty() const { return _isDirty; }
|
||||||
void clearDirtyBit() { _isDirty = false; }
|
void clearDirtyBit() { _isDirty = false; }
|
||||||
|
void setDirtyBit() { _isDirty = true; }
|
||||||
bool hasChangedSince(uint64_t time) const { return (_lastChanged > time); }
|
bool hasChangedSince(uint64_t time) const { return (_lastChanged > time); }
|
||||||
void markWithChangedTime() { _lastChanged = usecTimestampNow(); }
|
void markWithChangedTime() { _lastChanged = usecTimestampNow(); }
|
||||||
uint64_t getLastChanged() const { return _lastChanged; }
|
uint64_t getLastChanged() const { return _lastChanged; }
|
||||||
|
|
Loading…
Reference in a new issue