mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:24:00 +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
|
||||
========
|
||||
|
||||
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
|
||||
you to run the full stack of the virtual world should you choose to.
|
||||
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
#include "Agent.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),
|
||||
_lookingAlongX(false),
|
||||
_lookingAwayFromOrigin(true),
|
||||
_isLookingAtOtherAvatar(false),
|
||||
_lookatTargetAvatar(NULL),
|
||||
_lookatIndicatorScale(1.0f),
|
||||
_perfStatsOn(false),
|
||||
_chatEntryOn(false),
|
||||
|
@ -151,6 +151,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
|
||||
NodeList::getInstance()->addHook(&_voxels);
|
||||
NodeList::getInstance()->addHook(this);
|
||||
NodeList::getInstance()->addDomainListener(this);
|
||||
|
||||
|
||||
// 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() {
|
||||
NodeList::getInstance()->removeHook(&_voxels);
|
||||
NodeList::getInstance()->removeHook(this);
|
||||
NodeList::getInstance()->removeDomainListener(this);
|
||||
|
||||
_sharedVoxelSystem.changeTree(new VoxelTree);
|
||||
|
||||
|
@ -309,8 +311,6 @@ void Application::initializeGL() {
|
|||
char title[50];
|
||||
sprintf(title, "Interface: %4.2f seconds\n", startupTime);
|
||||
qDebug("%s", title);
|
||||
_window->setWindowTitle(title);
|
||||
|
||||
const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
|
||||
|
||||
// ask the Logstash class to record the startup time
|
||||
|
@ -389,6 +389,7 @@ void Application::paintGL() {
|
|||
|
||||
} else {
|
||||
_glowEffect.prepare();
|
||||
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
|
@ -541,6 +542,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
_myAvatar.setDriveKeys(UP, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Asterisk:
|
||||
Menu::getInstance()->triggerOption(MenuOption::Stars);
|
||||
break;
|
||||
|
||||
case Qt::Key_C:
|
||||
if (isShifted) {
|
||||
|
@ -810,8 +815,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
case Qt::Key_F:
|
||||
if (isShifted) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::DisplayFrustum);
|
||||
} else {
|
||||
Menu::getInstance()->triggerOption(MenuOption::Fullscreen);
|
||||
}
|
||||
break;
|
||||
case Qt::Key_V:
|
||||
|
@ -974,7 +977,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
|||
|
||||
maybeEditVoxelUnderCursor();
|
||||
|
||||
if (!_palette.isActive() && (!_isHoverVoxel || _isLookingAtOtherAvatar)) {
|
||||
if (!_palette.isActive() && (!_isHoverVoxel || _lookatTargetAvatar)) {
|
||||
_pieMenu.mousePressEvent(_mouseX, _mouseY);
|
||||
}
|
||||
|
||||
|
@ -998,6 +1001,17 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
|||
|
||||
_audio.startCollisionSound(1.0, frequency, 0.0, HOVER_VOXEL_DECAY);
|
||||
_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()) {
|
||||
|
@ -1503,7 +1517,7 @@ void Application::setListenModeSingleSource() {
|
|||
glm::vec3 eyePositionIgnored;
|
||||
uint16_t nodeID;
|
||||
|
||||
if (isLookingAtOtherAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeID)) {
|
||||
if (findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeID)) {
|
||||
_audio.addListenSource(nodeID);
|
||||
}
|
||||
}
|
||||
|
@ -1518,7 +1532,6 @@ void Application::initDisplay() {
|
|||
}
|
||||
|
||||
void Application::init() {
|
||||
_voxels.init();
|
||||
_sharedVoxelSystemViewFrustum.setPosition(glm::vec3(TREE_SCALE / 2.0f,
|
||||
TREE_SCALE / 2.0f,
|
||||
3.0f * TREE_SCALE / 2.0f));
|
||||
|
@ -1539,6 +1552,7 @@ void Application::init() {
|
|||
|
||||
_glowEffect.init();
|
||||
_ambientOcclusionEffect.init();
|
||||
_voxelShader.init();
|
||||
|
||||
_handControl.setScreenDimensions(_glWidget->width(), _glWidget->height());
|
||||
|
||||
|
@ -1569,9 +1583,15 @@ void Application::init() {
|
|||
if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) {
|
||||
_audio.setJitterBufferSamples(Menu::getInstance()->getAudioJitterBufferSamples());
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
_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 HEAD_SPHERE_RADIUS = 0.07;
|
||||
|
||||
|
||||
static uint16_t DEFAULT_NODE_ID_REF = 1;
|
||||
|
||||
|
||||
Avatar* Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||
glm::vec3& eyePosition, uint16_t& nodeID = DEFAULT_NODE_ID_REF) {
|
||||
void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||
glm::vec3& eyePosition) {
|
||||
|
||||
_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();
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
|
@ -1739,6 +1763,11 @@ void Application::update(float deltaTime) {
|
|||
|
||||
// Update faceshift
|
||||
_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
|
||||
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);
|
||||
}
|
||||
|
||||
_isLookingAtOtherAvatar = isLookingAtOtherAvatar(lookAtRayOrigin, lookAtRayDirection, lookAtSpot);
|
||||
if (_isLookingAtOtherAvatar) {
|
||||
updateLookatTargetAvatar(lookAtRayOrigin, lookAtRayDirection, lookAtSpot);
|
||||
if (_lookatTargetAvatar) {
|
||||
// If the mouse is over another avatar's head...
|
||||
_myAvatar.getHead().setLookAtPosition(lookAtSpot);
|
||||
} else if (_isHoverVoxel && !_faceshift.isActive()) {
|
||||
|
@ -1921,7 +1950,7 @@ void Application::update(float deltaTime) {
|
|||
if (!avatar->isInitialized()) {
|
||||
avatar->init();
|
||||
}
|
||||
avatar->simulate(deltaTime, NULL, 0.f);
|
||||
avatar->simulate(deltaTime, NULL);
|
||||
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
|
||||
}
|
||||
node->unlock();
|
||||
|
@ -1936,9 +1965,9 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TransmitterDrive) && _myTransmitter.isConnected()) {
|
||||
_myAvatar.simulate(deltaTime, &_myTransmitter, Menu::getInstance()->getGyroCameraSensitivity());
|
||||
_myAvatar.simulate(deltaTime, &_myTransmitter);
|
||||
} else {
|
||||
_myAvatar.simulate(deltaTime, NULL, Menu::getInstance()->getGyroCameraSensitivity());
|
||||
_myAvatar.simulate(deltaTime, NULL);
|
||||
}
|
||||
|
||||
// no transmitter drive implies transmitter pick
|
||||
|
@ -2063,15 +2092,15 @@ void Application::updateAvatar(float deltaTime) {
|
|||
const float MIDPOINT_OF_SCREEN = 0.5;
|
||||
|
||||
// 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
|
||||
glm::vec3 screenCenterRayOrigin, screenCenterRayDirection;
|
||||
_viewFrustum.computePickRay(MIDPOINT_OF_SCREEN, MIDPOINT_OF_SCREEN, screenCenterRayOrigin, screenCenterRayDirection);
|
||||
|
||||
glm::vec3 eyePosition;
|
||||
_isLookingAtOtherAvatar = isLookingAtOtherAvatar(screenCenterRayOrigin, screenCenterRayDirection, eyePosition);
|
||||
if (_isLookingAtOtherAvatar) {
|
||||
updateLookatTargetAvatar(screenCenterRayOrigin, screenCenterRayDirection, eyePosition);
|
||||
if (_lookatTargetAvatar) {
|
||||
glm::vec3 myLookAtFromMouse(eyePosition);
|
||||
_myAvatar.getHead().setLookAtPosition(myLookAtFromMouse);
|
||||
}
|
||||
|
@ -2540,7 +2569,7 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls));
|
||||
_myAvatar.setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::LookAtIndicator) && _isLookingAtOtherAvatar) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::LookAtIndicator) && _lookatTargetAvatar) {
|
||||
renderLookatIndicator(_lookatOtherPosition, whichCamera);
|
||||
}
|
||||
}
|
||||
|
@ -2561,7 +2590,7 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) {
|
||||
renderViewFrustum(_viewFrustum);
|
||||
}
|
||||
|
||||
|
||||
// render voxel fades if they exist
|
||||
if (_voxelFades.size() > 0) {
|
||||
for(std::vector<VoxelFade>::iterator fade = _voxelFades.begin(); fade != _voxelFades.end();) {
|
||||
|
@ -2806,28 +2835,39 @@ void Application::displayStats() {
|
|||
|
||||
std::stringstream voxelStats;
|
||||
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());
|
||||
|
||||
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("");
|
||||
char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS);
|
||||
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("");
|
||||
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ELAPSED);
|
||||
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("");
|
||||
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ENCODE);
|
||||
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("");
|
||||
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_MODE);
|
||||
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);
|
||||
char avatarMixerStats[200];
|
||||
|
@ -2840,7 +2880,7 @@ void Application::displayStats() {
|
|||
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());
|
||||
|
||||
if (_perfStatsOn) {
|
||||
|
@ -3342,10 +3382,7 @@ void Application::toggleFollowMode() {
|
|||
mouseRayOrigin, mouseRayDirection);
|
||||
glm::vec3 eyePositionIgnored;
|
||||
uint16_t nodeIDIgnored;
|
||||
Avatar* leadingAvatar = isLookingAtOtherAvatar(mouseRayOrigin,
|
||||
mouseRayDirection,
|
||||
eyePositionIgnored,
|
||||
nodeIDIgnored);
|
||||
Avatar* leadingAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeIDIgnored);
|
||||
|
||||
_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) {
|
||||
}
|
||||
|
||||
|
@ -3418,6 +3460,8 @@ void Application::nodeKilled(Node* node) {
|
|||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||
_voxelFades.push_back(fade);
|
||||
}
|
||||
} else if (node->getLinkedData() == _lookatTargetAvatar) {
|
||||
_lookatTargetAvatar = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "renderer/AmbientOcclusionEffect.h"
|
||||
#include "renderer/GeometryCache.h"
|
||||
#include "renderer/GlowEffect.h"
|
||||
#include "renderer/VoxelShader.h"
|
||||
#include "renderer/TextureCache.h"
|
||||
#include "ui/BandwidthDialog.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_BLUE = 0.0f;
|
||||
|
||||
class Application : public QApplication, public NodeListHook, public PacketSenderNotify {
|
||||
class Application : public QApplication, public NodeListHook, public PacketSenderNotify, public DomainChangeListener {
|
||||
Q_OBJECT
|
||||
|
||||
friend class VoxelPacketProcessor;
|
||||
|
@ -130,6 +131,8 @@ public:
|
|||
TextureCache* getTextureCache() { return &_textureCache; }
|
||||
GlowEffect* getGlowEffect() { return &_glowEffect; }
|
||||
|
||||
Avatar* getLookatTargetAvatar() const { return _lookatTargetAvatar; }
|
||||
|
||||
static void controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes,
|
||||
const char* nodeTypes, int numNodeTypes);
|
||||
|
||||
|
@ -142,6 +145,10 @@ public:
|
|||
virtual void nodeAdded(Node* node);
|
||||
virtual void nodeKilled(Node* node);
|
||||
virtual void packetSentNotification(ssize_t length);
|
||||
|
||||
virtual void domainChanged(QString domain);
|
||||
|
||||
VoxelShader& getVoxelShader() { return _voxelShader; }
|
||||
|
||||
public slots:
|
||||
void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data);
|
||||
|
@ -195,8 +202,11 @@ private:
|
|||
void init();
|
||||
|
||||
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);
|
||||
|
||||
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);
|
||||
|
@ -315,7 +325,7 @@ private:
|
|||
bool _lookingAwayFromOrigin;
|
||||
glm::vec3 _nudgeGuidePosition;
|
||||
|
||||
bool _isLookingAtOtherAvatar;
|
||||
Avatar* _lookatTargetAvatar;
|
||||
glm::vec3 _lookatOtherPosition;
|
||||
float _lookatIndicatorScale;
|
||||
|
||||
|
@ -341,6 +351,7 @@ private:
|
|||
|
||||
GlowEffect _glowEffect;
|
||||
AmbientOcclusionEffect _ambientOcclusionEffect;
|
||||
VoxelShader _voxelShader;
|
||||
|
||||
#ifndef _WIN32
|
||||
Audio _audio;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <QFormLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QMainWindow>
|
||||
#include <QSlider>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "Application.h"
|
||||
|
@ -48,7 +49,8 @@ Menu::Menu() :
|
|||
_frustumDrawMode(FRUSTUM_DRAW_MODE_ALL),
|
||||
_viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET),
|
||||
_voxelModeActionsGroup(NULL),
|
||||
_voxelStatsDialog(NULL)
|
||||
_voxelStatsDialog(NULL),
|
||||
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM)
|
||||
{
|
||||
Application *appInstance = Application::getInstance();
|
||||
|
||||
|
@ -188,50 +190,36 @@ Menu::Menu() :
|
|||
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||
MenuOption::Fullscreen,
|
||||
Qt::Key_F,
|
||||
Qt::CTRL | Qt::META | Qt::Key_F,
|
||||
false,
|
||||
appInstance,
|
||||
SLOT(setFullscreen(bool)));
|
||||
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,
|
||||
Qt::Key_Plus,
|
||||
appInstance->getAvatar(),
|
||||
SLOT(increaseSize()));
|
||||
addActionToQMenuAndActionHash(viewMenu,
|
||||
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||
MenuOption::DecreaseAvatarSize,
|
||||
Qt::Key_Minus,
|
||||
appInstance->getAvatar(),
|
||||
SLOT(decreaseSize()));
|
||||
addActionToQMenuAndActionHash(viewMenu,
|
||||
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||
MenuOption::ResetAvatarSize,
|
||||
0,
|
||||
appInstance->getAvatar(),
|
||||
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,
|
||||
MenuOption::OffAxisProjection,
|
||||
0,
|
||||
false);
|
||||
|
||||
|
||||
addDisabledActionAndSeparator(viewMenu, "Stats");
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L);
|
||||
|
@ -241,50 +229,126 @@ Menu::Menu() :
|
|||
addActionToQMenuAndActionHash(viewMenu, MenuOption::VoxelStats, 0, this, SLOT(voxelStatsDetails()));
|
||||
|
||||
QMenu* developerMenu = addMenu("Developer");
|
||||
addDisabledActionAndSeparator(developerMenu, "Rendering");
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
||||
|
||||
QMenu* renderOptionsMenu = developerMenu->addMenu("Rendering Options");
|
||||
|
||||
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,
|
||||
Qt::SHIFT | Qt::Key_V,
|
||||
true,
|
||||
appInstance,
|
||||
SLOT(setRenderVoxels(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::VoxelTextures);
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::AmbientOcclusion);
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stars, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true);
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::GroundPlane, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Avatars, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::AvatarAsBalls);
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0,
|
||||
false, this, SLOT(switchVoxelShader()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseByteNormals, 0,
|
||||
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,
|
||||
0,
|
||||
appInstance->getAvatar()->getVoxels(),
|
||||
SLOT(cycleMode()));
|
||||
|
||||
addActionToQMenuAndActionHash(developerMenu,
|
||||
addActionToQMenuAndActionHash(avatarOptionsMenu,
|
||||
MenuOption::FaceMode,
|
||||
0,
|
||||
&appInstance->getAvatar()->getHead().getFace(),
|
||||
SLOT(cycleRenderMode()));
|
||||
|
||||
addActionToQMenuAndActionHash(developerMenu,
|
||||
MenuOption::GlowMode,
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::UsePerlinFace, 0, false);
|
||||
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,
|
||||
appInstance->getGlowEffect(),
|
||||
SLOT(cycleRenderMode()));
|
||||
appInstance->getWebcam()->getGrabber(),
|
||||
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(developerMenu, MenuOption::LookAtVectors, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::LookAtIndicator, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::FrameTimer);
|
||||
addCheckableActionToQMenuAndActionHash(trackingOptionsMenu,
|
||||
MenuOption::LEDTracking,
|
||||
0,
|
||||
false,
|
||||
appInstance->getWebcam()->getGrabber(),
|
||||
SLOT(setLEDTrackingOn(bool)));
|
||||
|
||||
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");
|
||||
addCheckableActionToQMenuAndActionHash(frustumMenu, MenuOption::DisplayFrustum, Qt::SHIFT | Qt::Key_F);
|
||||
|
||||
addActionToQMenuAndActionHash(frustumMenu,
|
||||
MenuOption::FrustumRenderMode,
|
||||
Qt::SHIFT | Qt::Key_R,
|
||||
|
@ -292,12 +356,6 @@ Menu::Menu() :
|
|||
SLOT(cycleFrustumRenderMode()));
|
||||
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");
|
||||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings);
|
||||
|
@ -337,18 +395,6 @@ Menu::Menu() :
|
|||
appInstance->getVoxels(),
|
||||
SLOT(falseColorizeInView()));
|
||||
|
||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||
MenuOption::FalseColorOccluded,
|
||||
0,
|
||||
appInstance->getVoxels(),
|
||||
SLOT(falseColorizeOccluded()));
|
||||
|
||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||
MenuOption::FalseColorOccludedV2,
|
||||
0,
|
||||
appInstance->getVoxels(),
|
||||
SLOT(falseColorizeOccludedV2()));
|
||||
|
||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||
MenuOption::FalseColorBySource,
|
||||
0,
|
||||
|
@ -361,32 +407,21 @@ Menu::Menu() :
|
|||
appInstance->getVoxels(),
|
||||
SLOT(trueColorize()));
|
||||
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
||||
MenuOption::Webcam,
|
||||
0,
|
||||
false,
|
||||
appInstance->getWebcam(),
|
||||
SLOT(setEnabled(bool)));
|
||||
|
||||
addActionToQMenuAndActionHash(developerMenu,
|
||||
MenuOption::WebcamMode,
|
||||
addDisabledActionAndSeparator(renderDebugMenu, "Coverage Maps");
|
||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||
MenuOption::FalseColorOccluded,
|
||||
0,
|
||||
appInstance->getWebcam()->getGrabber(),
|
||||
SLOT(cycleVideoSendMode()));
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
||||
MenuOption::WebcamTexture,
|
||||
0,
|
||||
false,
|
||||
appInstance->getWebcam()->getGrabber(),
|
||||
SLOT(setDepthOnly(bool)));
|
||||
appInstance->getVoxels(),
|
||||
SLOT(falseColorizeOccluded()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
||||
MenuOption::FaceshiftTCP,
|
||||
0,
|
||||
false,
|
||||
appInstance->getFaceshift(),
|
||||
SLOT(setTCPEnabled(bool)));
|
||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||
MenuOption::FalseColorOccludedV2,
|
||||
0,
|
||||
appInstance->getVoxels(),
|
||||
SLOT(falseColorizeOccludedV2()));
|
||||
|
||||
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");
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoAudio);
|
||||
|
@ -406,47 +441,38 @@ Menu::Menu() :
|
|||
appInstance,
|
||||
SLOT(setListenModeSingleSource()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::TestPing, 0, true);
|
||||
QMenu* voxelProtoOptionsMenu = developerMenu->addMenu("Voxel Server Protocol Options");
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
||||
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu,
|
||||
MenuOption::SendVoxelColors,
|
||||
0,
|
||||
true,
|
||||
appInstance->getAvatar(),
|
||||
SLOT(setWantColor(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
||||
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu,
|
||||
MenuOption::LowRes,
|
||||
0,
|
||||
true,
|
||||
appInstance->getAvatar(),
|
||||
SLOT(setWantLowResMoving(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
||||
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu,
|
||||
MenuOption::DeltaSending,
|
||||
0,
|
||||
true,
|
||||
appInstance->getAvatar(),
|
||||
SLOT(setWantDelta(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu,
|
||||
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu,
|
||||
MenuOption::OcclusionCulling,
|
||||
Qt::SHIFT | Qt::Key_C,
|
||||
true,
|
||||
appInstance->getAvatar(),
|
||||
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
|
||||
QMenu* helpMenu = addMenu("Help");
|
||||
QAction* helpAction = helpMenu->addAction(MenuOption::AboutApp);
|
||||
|
@ -465,9 +491,9 @@ void Menu::loadSettings(QSettings* settings) {
|
|||
settings = Application::getInstance()->getSettings();
|
||||
}
|
||||
|
||||
_gyroCameraSensitivity = loadSetting(settings, "gyroCameraSensitivity", 0.5f);
|
||||
_audioJitterBufferSamples = loadSetting(settings, "audioJitterBufferSamples", 0);
|
||||
_fieldOfView = loadSetting(settings, "fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES);
|
||||
_maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
||||
|
||||
settings->beginGroup("View Frustum Offset Camera");
|
||||
// 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->setValue("gyroCameraSensitivity", _gyroCameraSensitivity);
|
||||
settings->setValue("audioJitterBufferSamples", _audioJitterBufferSamples);
|
||||
settings->setValue("fieldOfView", _fieldOfView);
|
||||
settings->setValue("maxVoxels", _maxVoxels);
|
||||
settings->beginGroup("View Frustum Offset Camera");
|
||||
settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw);
|
||||
settings->setValue("viewFrustumOffsetPitch", _viewFrustumOffset.pitch);
|
||||
|
@ -738,9 +764,6 @@ void Menu::editPreferences() {
|
|||
QFormLayout* form = new QFormLayout();
|
||||
layout->addLayout(form, 1);
|
||||
|
||||
QLineEdit* domainServerLineEdit = lineEditForDomainHostname();
|
||||
form->addRow("Domain server:", domainServerLineEdit);
|
||||
|
||||
QLineEdit* avatarURL = new QLineEdit(applicationInstance->getAvatar()->getVoxels()->getVoxelURL().toString());
|
||||
avatarURL->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
form->addRow("Avatar URL:", avatarURL);
|
||||
|
@ -749,16 +772,16 @@ void Menu::editPreferences() {
|
|||
faceURL->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
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();
|
||||
fieldOfView->setMaximum(180);
|
||||
fieldOfView->setMinimum(1);
|
||||
fieldOfView->setValue(_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();
|
||||
leanScale->setValue(applicationInstance->getAvatar()->getLeanScale());
|
||||
form->addRow("Lean Scale:", leanScale);
|
||||
|
@ -768,6 +791,16 @@ void Menu::editPreferences() {
|
|||
audioJitterBufferSamples->setMinimum(-10000);
|
||||
audioJitterBufferSamples->setValue(_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);
|
||||
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||
|
@ -780,8 +813,6 @@ void Menu::editPreferences() {
|
|||
return;
|
||||
}
|
||||
|
||||
updateDSHostname(domainServerLineEdit->text());
|
||||
|
||||
QUrl avatarVoxelURL(avatarURL->text());
|
||||
applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL);
|
||||
|
||||
|
@ -790,7 +821,10 @@ void Menu::editPreferences() {
|
|||
|
||||
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());
|
||||
|
||||
|
@ -990,3 +1024,8 @@ void Menu::updateFrustumRenderModeAction() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::switchVoxelShader() {
|
||||
Application::getInstance()->getVoxels()->setUseVoxelShader(isOptionChecked(MenuOption::UseVoxelShader));
|
||||
}
|
||||
|
||||
|
|
|
@ -49,11 +49,12 @@ public:
|
|||
|
||||
float getAudioJitterBufferSamples() const { return _audioJitterBufferSamples; }
|
||||
float getFieldOfView() const { return _fieldOfView; }
|
||||
float getGyroCameraSensitivity() const { return _gyroCameraSensitivity; }
|
||||
BandwidthDialog* getBandwidthDialog() const { return _bandwidthDialog; }
|
||||
FrustumDrawMode getFrustumDrawMode() const { return _frustumDrawMode; }
|
||||
ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; }
|
||||
VoxelStatsDialog* getVoxelStatsDialog() const { return _voxelStatsDialog; }
|
||||
int getMaxVoxels() const { return _maxVoxels; }
|
||||
|
||||
|
||||
void handleViewFrustumOffsetKeyModifier(int key);
|
||||
|
||||
|
@ -78,6 +79,7 @@ private slots:
|
|||
void chooseVoxelPaintColor();
|
||||
void runTests();
|
||||
void resetSwatchColors();
|
||||
void switchVoxelShader();
|
||||
|
||||
private:
|
||||
static Menu* _instance;
|
||||
|
@ -111,10 +113,10 @@ private:
|
|||
BandwidthDialog* _bandwidthDialog;
|
||||
float _fieldOfView; /// in Degrees, doesn't apply to HMD like Oculus
|
||||
FrustumDrawMode _frustumDrawMode;
|
||||
float _gyroCameraSensitivity;
|
||||
ViewFrustumOffset _viewFrustumOffset;
|
||||
QActionGroup* _voxelModeActionsGroup;
|
||||
VoxelStatsDialog* _voxelStatsDialog;
|
||||
int _maxVoxels;
|
||||
};
|
||||
|
||||
namespace MenuOption {
|
||||
|
@ -201,9 +203,9 @@ namespace MenuOption {
|
|||
const QString TransmitterDrive = "Transmitter Drive";
|
||||
const QString UsePerlinFace = "Use Perlin's Face";
|
||||
const QString Quit = "Quit";
|
||||
const QString Webcam = "Webcam";
|
||||
const QString WebcamMode = "Cycle Webcam Send Mode";
|
||||
const QString WebcamTexture = "Webcam Texture";
|
||||
const QString UseVoxelShader = "Use Voxel Shader";
|
||||
const QString UseByteNormals = "Use Byte Normals";
|
||||
const QString UseGlobalNormals = "Use Global Normals";
|
||||
const QString Voxels = "Voxels";
|
||||
const QString VoxelAddMode = "Add Voxel Mode";
|
||||
const QString VoxelColorMode = "Color Voxel Mode";
|
||||
|
@ -214,6 +216,9 @@ namespace MenuOption {
|
|||
const QString VoxelSelectMode = "Select Voxel Mode";
|
||||
const QString VoxelStats = "Voxel Stats";
|
||||
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__) */
|
||||
|
|
|
@ -33,9 +33,11 @@
|
|||
#include "VoxelConstants.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,
|
||||
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 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 };
|
||||
|
||||
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,
|
||||
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+
|
||||
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)
|
||||
: NodeData(NULL),
|
||||
_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(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) {
|
||||
|
@ -119,21 +143,7 @@ void VoxelSystem::clearFreeBufferIndexes() {
|
|||
}
|
||||
|
||||
VoxelSystem::~VoxelSystem() {
|
||||
if (_initialized) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
cleanupVoxelMemory();
|
||||
delete _tree;
|
||||
pthread_mutex_destroy(&_bufferWriteLock);
|
||||
pthread_mutex_destroy(&_treeLock);
|
||||
|
@ -141,6 +151,321 @@ VoxelSystem::~VoxelSystem() {
|
|||
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) {
|
||||
_tree->loadVoxelsFile(fileName, wantColorRandomizer);
|
||||
setupNewVoxelsForDrawing();
|
||||
|
@ -398,18 +723,27 @@ void VoxelSystem::copyWrittenDataToReadArraysPartialVBOs() {
|
|||
|
||||
void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
|
||||
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);
|
||||
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
||||
GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes);
|
||||
GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat);
|
||||
GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat);
|
||||
GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * vertexPointsPerVoxel);
|
||||
GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * vertexPointsPerVoxel);
|
||||
memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes);
|
||||
|
||||
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
||||
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
||||
GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
memcpy(readColorsAt, writeColorsAt, segmentSizeBytes);
|
||||
segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte);
|
||||
segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte);
|
||||
GLubyte* readColorsAt = _readColorsArray + (segmentStart * vertexPointsPerVoxel);
|
||||
GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * vertexPointsPerVoxel);
|
||||
memcpy(readColorsAt, writeColorsAt, segmentSizeBytes);
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) {
|
||||
|
@ -532,11 +866,34 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) {
|
|||
|
||||
void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex,
|
||||
float voxelScale, const nodeColor& color) {
|
||||
for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) {
|
||||
GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
||||
GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
||||
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
||||
*(writeColorsAt +j) = color[j % 3];
|
||||
|
||||
if (_useVoxelShader) {
|
||||
if (_writeVoxelShaderData) {
|
||||
VoxelShaderVBOData* writeVerticesAt = &_writeVoxelShaderData[nodeIndex];
|
||||
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;
|
||||
_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
|
||||
glGenBuffers(1, &_vboVerticesID);
|
||||
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();
|
||||
}
|
||||
initVoxelMemory();
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
|
@ -714,17 +993,28 @@ void VoxelSystem::updateVBOs() {
|
|||
}
|
||||
|
||||
void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
|
||||
int segmentLength = (segmentEnd - segmentStart) + 1;
|
||||
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
||||
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
||||
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
||||
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
||||
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
|
||||
if (_useVoxelShader) {
|
||||
int segmentLength = (segmentEnd - segmentStart) + 1;
|
||||
GLintptr segmentStartAt = segmentStart * sizeof(VoxelShaderVBOData);
|
||||
GLsizeiptr segmentSizeBytes = segmentLength * sizeof(VoxelShaderVBOData);
|
||||
void* readVerticesFrom = &_readVoxelShaderData[segmentStart];
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||
} else {
|
||||
int vertexPointsPerVoxel = _useGlobalNormals ? GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL : VERTEX_POINTS_PER_VOXEL;
|
||||
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) {
|
||||
|
@ -734,43 +1024,116 @@ void VoxelSystem::render(bool texture) {
|
|||
pthread_mutex_lock(&_bufferWriteLock);
|
||||
|
||||
updateVBOs();
|
||||
|
||||
if (_useVoxelShader) {
|
||||
|
||||
// tell OpenGL where to find vertex and color information
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
Application::getInstance()->getVoxelShader().begin();
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
//Define this somewhere in your header file
|
||||
#define BUFFER_OFFSET(i) ((void*)(i))
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
||||
glNormalPointer(GL_FLOAT, 0, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID);
|
||||
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);
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID);
|
||||
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
|
||||
glEnable(GL_CULL_FACE);
|
||||
// for performance, enable backface culling
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
// draw the number of voxels we have
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
if (!_useGlobalNormals) {
|
||||
// draw the number of voxels we have
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
||||
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
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
// 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);
|
||||
if (!_useGlobalNormals) {
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
}
|
||||
|
||||
// bind with 0 to switch back to normal operation
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
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) {
|
||||
_nodeCount++;
|
||||
if (node->isColored()) {
|
||||
|
@ -1203,7 +1594,7 @@ public:
|
|||
duplicateVBOIndex(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;
|
||||
|
@ -1218,7 +1609,7 @@ public:
|
|||
|
||||
unsigned long expectedMax;
|
||||
|
||||
bool hasIndexFound[MAX_VOXELS_PER_SYSTEM];
|
||||
bool hasIndexFound[DEFAULT_MAX_VOXELS_PER_SYSTEM];
|
||||
};
|
||||
|
||||
bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData) {
|
||||
|
@ -1293,7 +1684,7 @@ void VoxelSystem::collectStatsForTreesAndVBOs() {
|
|||
glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN;
|
||||
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]) {
|
||||
minInVBO = std::min(minInVBO,i);
|
||||
maxInVBO = std::max(maxInVBO,i);
|
||||
|
@ -1622,7 +2013,7 @@ void VoxelSystem::falseColorizeOccludedV2() {
|
|||
void VoxelSystem::nodeAdded(Node* node) {
|
||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||
uint16_t nodeID = node->getNodeID();
|
||||
printf("VoxelSystem... voxel server %u added...\n", nodeID);
|
||||
qDebug("VoxelSystem... voxel server %u added...\n", nodeID);
|
||||
_voxelServerCount++;
|
||||
}
|
||||
}
|
||||
|
@ -1645,7 +2036,7 @@ void VoxelSystem::nodeKilled(Node* node) {
|
|||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||
_voxelServerCount--;
|
||||
uint16_t nodeID = node->getNodeID();
|
||||
printf("VoxelSystem... voxel server %u removed...\n", nodeID);
|
||||
qDebug("VoxelSystem... voxel server %u removed...\n", nodeID);
|
||||
|
||||
if (_voxelServerCount > 0) {
|
||||
// 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 "Util.h"
|
||||
#include "world.h"
|
||||
#include "renderer/VoxelShader.h"
|
||||
|
||||
class ProgramObject;
|
||||
|
||||
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 {
|
||||
Q_OBJECT
|
||||
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();
|
||||
|
||||
void setDataSourceID(int dataSourceID) { _dataSourceID = dataSourceID; }
|
||||
|
@ -56,6 +65,14 @@ public:
|
|||
bool readFromSquareARGB32Pixels(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 getVoxelsColored();
|
||||
long int getVoxelsBytesRead();
|
||||
|
@ -113,8 +130,12 @@ public slots:
|
|||
void falseColorizeOccluded();
|
||||
void falseColorizeOccludedV2();
|
||||
void falseColorizeBySource();
|
||||
void forceRedrawEntireTree();
|
||||
void clearAllNodesBufferIndex();
|
||||
|
||||
void cancelImport();
|
||||
void setUseByteNormals(bool useByteNormals);
|
||||
void setUseGlobalNormals(bool useGlobalNormals);
|
||||
|
||||
protected:
|
||||
float _treeScale;
|
||||
|
@ -158,6 +179,8 @@ private:
|
|||
static bool falseColorizeOccludedV2Operation(VoxelNode* node, void* extraData);
|
||||
static bool falseColorizeBySourceOperation(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 updateNodeInArraysAsPartialVBO(VoxelNode* node);
|
||||
|
@ -167,6 +190,8 @@ private:
|
|||
|
||||
void updateVBOs();
|
||||
|
||||
unsigned long getFreeMemoryGPU();
|
||||
|
||||
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
|
||||
static float _maxDistance;
|
||||
static float _minDistance;
|
||||
|
@ -190,10 +215,30 @@ private:
|
|||
uint64_t _lastViewCulling;
|
||||
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 _vboNormalsID;
|
||||
GLuint _vboColorsID;
|
||||
GLuint _vboIndicesID;
|
||||
|
||||
GLuint _vboIndicesTop;
|
||||
GLuint _vboIndicesBottom;
|
||||
GLuint _vboIndicesLeft;
|
||||
GLuint _vboIndicesRight;
|
||||
GLuint _vboIndicesFront;
|
||||
GLuint _vboIndicesBack;
|
||||
|
||||
pthread_mutex_t _bufferWriteLock;
|
||||
pthread_mutex_t _treeLock;
|
||||
|
||||
|
@ -201,6 +246,8 @@ private:
|
|||
ViewFrustum _lastStableViewFrustum;
|
||||
ViewFrustum* _viewFrustum;
|
||||
|
||||
void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]);
|
||||
|
||||
int newTreeToArrays(VoxelNode *currentNode);
|
||||
void cleanupRemovedVoxels();
|
||||
|
||||
|
@ -224,6 +271,10 @@ private:
|
|||
int _dataSourceID;
|
||||
|
||||
int _voxelServerCount;
|
||||
unsigned long _memoryUsageRAM;
|
||||
unsigned long _memoryUsageVBO;
|
||||
unsigned long _initialMemoryUsageGPU;
|
||||
bool _hasMemoryUsageGPU;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
using namespace std;
|
||||
|
||||
const bool BALLS_ON = false;
|
||||
const bool USING_AVATAR_GRAVITY = true;
|
||||
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
||||
const float YAW_MAG = 500.0;
|
||||
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::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.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position);
|
||||
_head.setScale(_scale);
|
||||
_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);
|
||||
|
||||
// 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());
|
||||
_head.getBlendFace().setModelURL(settings->value("faceModelURL").toUrl());
|
||||
_head.setPupilDilation(settings->value("pupilDilation", 0.0f).toFloat());
|
||||
|
||||
_leanScale = loadSetting(settings, "leanScale", 0.05f);
|
||||
|
||||
|
@ -811,6 +822,7 @@ void Avatar::saveData(QSettings* set) {
|
|||
|
||||
set->setValue("voxelURL", _voxels.getVoxelURL());
|
||||
set->setValue("faceModelURL", _head.getBlendFace().getModelURL());
|
||||
set->setValue("pupilDilation", _head.getPupilDilation());
|
||||
|
||||
set->setValue("leanScale", _leanScale);
|
||||
set->setValue("scale", _newScale);
|
||||
|
|
|
@ -135,7 +135,7 @@ public:
|
|||
~Avatar();
|
||||
|
||||
void init();
|
||||
void simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity);
|
||||
void simulate(float deltaTime, Transmitter* transmitter);
|
||||
void follow(Avatar* leadingAvatar);
|
||||
void render(bool lookingInMirror, bool renderAvatarBalls);
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ BlendFace::~BlendFace() {
|
|||
}
|
||||
|
||||
ProgramObject BlendFace::_eyeProgram;
|
||||
GLuint BlendFace::_eyeTextureID;
|
||||
DilatedTextureCache BlendFace::_eyeTextureCache("resources/images/eye.png", 50, 210);
|
||||
|
||||
void BlendFace::init() {
|
||||
if (!_eyeProgram.isLinked()) {
|
||||
|
@ -40,8 +40,6 @@ void BlendFace::init() {
|
|||
_eyeProgram.bind();
|
||||
_eyeProgram.setUniformValue("texture", 0);
|
||||
_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
|
||||
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);
|
||||
|
||||
_eyeProgram.bind();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "InterfaceConfig.h"
|
||||
#include "renderer/FBXReader.h"
|
||||
#include "renderer/ProgramObject.h"
|
||||
#include "renderer/TextureCache.h"
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
|
@ -62,8 +63,10 @@ private:
|
|||
QVector<glm::vec3> _blendedVertices;
|
||||
QVector<glm::vec3> _blendedNormals;
|
||||
|
||||
QSharedPointer<Texture> _eyeTexture;
|
||||
|
||||
static ProgramObject _eyeProgram;
|
||||
static GLuint _eyeTextureID;
|
||||
static DilatedTextureCache _eyeTextureCache;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__BlendFace__) */
|
||||
|
|
|
@ -29,7 +29,7 @@ const float EYEBALL_RADIUS = 0.017;
|
|||
const float EYELID_RADIUS = 0.019;
|
||||
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_GRAVITY_FORCE = 0.001f;
|
||||
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";
|
||||
|
||||
ProgramObject Head::_irisProgram;
|
||||
GLuint Head::_irisTextureID;
|
||||
DilatedTextureCache Head::_irisTextureCache(IRIS_TEXTURE_FILENAME, 53, 127);
|
||||
int Head::_eyePositionLocation;
|
||||
|
||||
Head::Head(Avatar* owningAvatar) :
|
||||
|
@ -71,6 +71,7 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_audioAttack(0.0f),
|
||||
_returnSpringScale(1.0f),
|
||||
_bodyRotation(0.0f, 0.0f, 0.0f),
|
||||
_angularVelocity(0,0,0),
|
||||
_renderLookatVectors(false),
|
||||
_mohawkInitialized(false),
|
||||
_saccade(0.0f, 0.0f, 0.0f),
|
||||
|
@ -102,13 +103,6 @@ void Head::init() {
|
|||
|
||||
_irisProgram.setUniformValue("texture", 0);
|
||||
_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();
|
||||
}
|
||||
|
@ -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
|
||||
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.
|
||||
if (USING_PHYSICAL_MOHAWK) {
|
||||
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();
|
||||
|
||||
_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);
|
||||
|
||||
// render left iris
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "PerlinFace.h"
|
||||
#include "world.h"
|
||||
#include "devices/SerialInterface.h"
|
||||
#include "renderer/TextureCache.h"
|
||||
|
||||
enum eyeContactTargets {
|
||||
LEFT_EYE,
|
||||
|
@ -43,7 +44,7 @@ public:
|
|||
|
||||
void init();
|
||||
void reset();
|
||||
void simulate(float deltaTime, bool isMine, float gyroCameraSensitivity);
|
||||
void simulate(float deltaTime, bool isMine);
|
||||
void render(float alpha, bool isMine);
|
||||
void renderMohawk();
|
||||
|
||||
|
@ -63,6 +64,8 @@ public:
|
|||
|
||||
glm::quat getOrientation() const;
|
||||
glm::quat getCameraOrientation () const;
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; }
|
||||
|
||||
float getScale() const { return _scale; }
|
||||
glm::vec3 getPosition() const { return _position; }
|
||||
|
@ -115,6 +118,7 @@ private:
|
|||
float _audioAttack;
|
||||
float _returnSpringScale; //strength of return springs
|
||||
glm::vec3 _bodyRotation;
|
||||
glm::vec3 _angularVelocity;
|
||||
bool _renderLookatVectors;
|
||||
BendyLine _hairTuft[NUM_HAIR_TUFTS];
|
||||
bool _mohawkInitialized;
|
||||
|
@ -135,8 +139,10 @@ private:
|
|||
PerlinFace _perlinFace;
|
||||
BlendFace _blendFace;
|
||||
|
||||
QSharedPointer<Texture> _irisTexture;
|
||||
|
||||
static ProgramObject _irisProgram;
|
||||
static GLuint _irisTextureID;
|
||||
static DilatedTextureCache _irisTextureCache;
|
||||
static int _eyePositionLocation;
|
||||
|
||||
// private methods
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
const bool USING_AVATAR_GRAVITY = true;
|
||||
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
||||
const float YAW_MAG = 500.0;
|
||||
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),
|
||||
_speedBrakes(false),
|
||||
_isThrustOn(false),
|
||||
_thrustMultiplier(1.0f)
|
||||
_thrustMultiplier(1.0f),
|
||||
_moveTarget(0,0,0),
|
||||
_moveTargetStepCounter(0)
|
||||
{
|
||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||
_driveKeys[i] = false;
|
||||
|
@ -65,7 +66,12 @@ void MyAvatar::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::vec3 front = orientation * IDENTITY_FRONT;
|
||||
|
@ -160,16 +166,16 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam
|
|||
_avatarTouch.simulate(deltaTime);
|
||||
|
||||
// apply gravity
|
||||
if (USING_AVATAR_GRAVITY) {
|
||||
// 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
|
||||
const float MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY = 0.02f;
|
||||
if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) {
|
||||
_velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime);
|
||||
}
|
||||
// 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
|
||||
const float MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY = 0.02f;
|
||||
if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) {
|
||||
_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();
|
||||
|
||||
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;
|
||||
applyStaticFriction(deltaTime, _velocity, MAX_STATIC_FRICTION_VELOCITY, STATIC_FRICTION_STRENGTH);
|
||||
|
||||
// Damp avatar velocity
|
||||
const float LINEAR_DAMPING_STRENGTH = 0.5f;
|
||||
const float SPEED_BRAKE_POWER = _scale * 10.0f;
|
||||
// Note: PER changed squared damping strength to zero
|
||||
const float SQUARED_DAMPING_STRENGTH = 0.0f;
|
||||
const float SQUARED_DAMPING_STRENGTH = 0.007f;
|
||||
|
||||
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) {
|
||||
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 {
|
||||
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
|
||||
const float BODY_PITCH_WHILE_WALKING = -20.0;
|
||||
const float BODY_ROLL_WHILE_TURNING = 0.2;
|
||||
float forwardComponentOfVelocity = glm::dot(getBodyFrontDirection(), _velocity);
|
||||
orientation = orientation * glm::quat(glm::radians(glm::vec3(
|
||||
BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity, 0.0f,
|
||||
BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta)));
|
||||
const float HIGH_VELOCITY = 10.f;
|
||||
if (glm::length(_velocity) < HIGH_VELOCITY) {
|
||||
const float BODY_PITCH_WHILE_WALKING = -20.0;
|
||||
const float BODY_ROLL_WHILE_TURNING = 0.2;
|
||||
float forwardComponentOfVelocity = glm::dot(getBodyFrontDirection(), _velocity);
|
||||
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...
|
||||
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.setScale(_scale);
|
||||
_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);
|
||||
|
||||
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;
|
||||
_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;
|
||||
|
||||
// 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()) {
|
||||
estimatedPosition = faceshift->getHeadTranslation();
|
||||
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()) {
|
||||
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 (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) {
|
||||
const float THRUST_INCREASE_RATE = 1.0;
|
||||
_thrustMultiplier *= 1.f + deltaTime * THRUST_INCREASE_RATE;
|
||||
const float THRUST_INCREASE_RATE = 1.05;
|
||||
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 {
|
||||
_thrustMultiplier = 1.f;
|
||||
}
|
||||
|
||||
// Add one time jumping force if requested
|
||||
if (_shouldJump) {
|
||||
_thrust += _scale * THRUST_JUMP * up;
|
||||
if (glm::length(_gravity) > EPSILON) {
|
||||
_thrust += _scale * THRUST_JUMP * up;
|
||||
}
|
||||
_shouldJump = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public:
|
|||
MyAvatar(Node* owningNode = NULL);
|
||||
|
||||
void reset();
|
||||
void simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity);
|
||||
void simulate(float deltaTime, Transmitter* transmitter);
|
||||
void updateFromGyrosAndOrWebcam(bool gyroLook, float pitchFromTouch);
|
||||
void render(bool lookingInMirror, bool renderAvatarBalls);
|
||||
void renderScreenTint(ScreenTintLayer layer, Camera& whichCamera);
|
||||
|
@ -31,6 +31,7 @@ public:
|
|||
void setOrientation(const glm::quat& orientation);
|
||||
void setNewScale(const float scale);
|
||||
void setWantCollisionsOn(bool wantCollisionsOn) { _isCollisionsOn = wantCollisionsOn; }
|
||||
void setMoveTarget(const glm::vec3 moveTarget);
|
||||
|
||||
// getters
|
||||
float getNewScale() const { return _newScale; }
|
||||
|
@ -73,6 +74,8 @@ public:
|
|||
bool _isThrustOn;
|
||||
float _thrustMultiplier;
|
||||
float _collisionRadius;
|
||||
glm::vec3 _moveTarget;
|
||||
int _moveTargetStepCounter;
|
||||
|
||||
// private methods
|
||||
float getBallRenderAlpha(int ball, bool lookingInMirror) const;
|
||||
|
|
|
@ -248,7 +248,11 @@ void PerlinFace::render() {
|
|||
|
||||
|
||||
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);
|
||||
|
||||
orientation = _owningHead->getOrientation();
|
||||
|
|
|
@ -142,8 +142,20 @@ void Faceshift::receive(const QByteArray& buffer) {
|
|||
case fsMsg::MSG_OUT_TRACKING_STATE: {
|
||||
const fsTrackingData& data = static_cast<fsMsgTrackingState*>(msg.get())->tracking_data();
|
||||
if ((_tracking = data.m_trackingSuccessful)) {
|
||||
_headRotation = glm::quat(data.m_headRotation.w, -data.m_headRotation.x,
|
||||
data.m_headRotation.y, -data.m_headRotation.z);
|
||||
glm::quat newRotation = glm::quat(data.m_headRotation.w, -data.m_headRotation.x,
|
||||
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;
|
||||
_headTranslation = glm::vec3(data.m_headTranslation.x, data.m_headTranslation.y,
|
||||
-data.m_headTranslation.z) * TRANSLATION_SCALE;
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
bool isActive() const;
|
||||
|
||||
const glm::quat& getHeadRotation() const { return _headRotation; }
|
||||
const glm::vec3& getHeadAngularVelocity() const { return _headAngularVelocity; }
|
||||
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
||||
|
||||
float getEyeGazeLeftPitch() const { return _eyeGazeLeftPitch; }
|
||||
|
@ -88,6 +89,7 @@ private:
|
|||
uint64_t _lastTrackingStateReceived;
|
||||
|
||||
glm::quat _headRotation;
|
||||
glm::vec3 _headAngularVelocity;
|
||||
glm::vec3 _headTranslation;
|
||||
|
||||
float _eyeGazeLeftPitch;
|
||||
|
|
|
@ -154,3 +154,44 @@ QOpenGLFramebufferObject* TextureCache::createFramebufferObject() {
|
|||
|
||||
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__
|
||||
|
||||
#include <QHash>
|
||||
#include <QImage>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <QWeakPointer>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
|
@ -62,4 +66,36 @@ private:
|
|||
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__) */
|
||||
|
|
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);
|
||||
}
|
||||
|
||||
// pupil dilation
|
||||
destinationBuffer += packFloatToByte(destinationBuffer, _headData->_pupilDilation, 1.0f);
|
||||
|
||||
// leap hand data
|
||||
destinationBuffer += _handData->encodeRemoteData(destinationBuffer);
|
||||
|
||||
|
@ -345,7 +348,10 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
_headData->_blendshapeCoefficients.size() * sizeof(float));
|
||||
sourceBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float);
|
||||
}
|
||||
|
||||
|
||||
// pupil dilation
|
||||
sourceBuffer += unpackFloatFromByte(sourceBuffer, _headData->_pupilDilation, 1.0f);
|
||||
|
||||
// leap hand data
|
||||
if (sourceBuffer - startPosition < numBytes) {
|
||||
// check passed, bytes match
|
||||
|
|
|
@ -46,6 +46,9 @@ public:
|
|||
|
||||
const std::vector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||
|
||||
float getPupilDilation() const { return _pupilDilation; }
|
||||
void setPupilDilation(float pupilDilation) { _pupilDilation = pupilDilation; }
|
||||
|
||||
void addYaw(float yaw);
|
||||
void addPitch(float pitch);
|
||||
void addRoll(float roll);
|
||||
|
@ -70,6 +73,7 @@ protected:
|
|||
float _averageLoudness;
|
||||
float _browAudioLift;
|
||||
std::vector<float> _blendshapeCoefficients;
|
||||
float _pupilDilation;
|
||||
AvatarData* _owningAvatar;
|
||||
|
||||
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
|
||||
_domainIP.clear();
|
||||
notifyDomainChanged();
|
||||
}
|
||||
|
||||
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
|
||||
|
@ -586,6 +587,7 @@ void NodeList::loadData(QSettings *settings) {
|
|||
|
||||
if (domainServerHostname.size() > 0) {
|
||||
_domainHostname = domainServerHostname;
|
||||
notifyDomainChanged();
|
||||
}
|
||||
|
||||
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) {
|
||||
_hooks.push_back(hook);
|
||||
}
|
||||
|
@ -705,3 +722,9 @@ void NodeList::notifyHooksOfKilledNode(Node* 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;
|
||||
};
|
||||
|
||||
class DomainChangeListener {
|
||||
public:
|
||||
virtual void domainChanged(QString domain) = 0;
|
||||
};
|
||||
|
||||
class NodeList {
|
||||
public:
|
||||
static NodeList* createInstance(char ownerType, unsigned short int socketListenPort = 0);
|
||||
|
@ -135,6 +140,9 @@ public:
|
|||
void notifyHooksOfAddedNode(Node* node);
|
||||
void notifyHooksOfKilledNode(Node* node);
|
||||
|
||||
void addDomainListener(DomainChangeListener* listener);
|
||||
void removeDomainListener(DomainChangeListener* listener);
|
||||
|
||||
private:
|
||||
static NodeList* _sharedInstance;
|
||||
|
||||
|
@ -166,6 +174,11 @@ private:
|
|||
void timePingReply(sockaddr *nodeAddress, unsigned char *packetData);
|
||||
|
||||
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> {
|
||||
|
|
|
@ -20,7 +20,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
|
|||
return 1;
|
||||
|
||||
case PACKET_TYPE_HEAD_DATA:
|
||||
return 7;
|
||||
return 8;
|
||||
|
||||
case PACKET_TYPE_AVATAR_URLS:
|
||||
return 1;
|
||||
|
|
|
@ -32,12 +32,18 @@ const float VOXEL_SIZE_SCALE = TREE_SCALE * 400.0f;
|
|||
const int NUMBER_OF_CHILDREN = 8;
|
||||
const int MAX_VOXEL_PACKET_SIZE = 1492;
|
||||
const int MAX_TREE_SLICE_BYTES = 26;
|
||||
const int MAX_VOXELS_PER_SYSTEM = 200000;
|
||||
const int VERTICES_PER_VOXEL = 24;
|
||||
const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
||||
const int INDICES_PER_VOXEL = 3 * 12;
|
||||
const int DEFAULT_MAX_VOXELS_PER_SYSTEM = 200000;
|
||||
const int VERTICES_PER_VOXEL = 24; // 6 sides * 4 corners per side
|
||||
const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; // xyz for each VERTICE_PER_VOXEL
|
||||
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 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;
|
||||
const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ public:
|
|||
void printDebugDetails(const char* label) const;
|
||||
bool isDirty() const { return _isDirty; }
|
||||
void clearDirtyBit() { _isDirty = false; }
|
||||
void setDirtyBit() { _isDirty = true; }
|
||||
bool hasChangedSince(uint64_t time) const { return (_lastChanged > time); }
|
||||
void markWithChangedTime() { _lastChanged = usecTimestampNow(); }
|
||||
uint64_t getLastChanged() const { return _lastChanged; }
|
||||
|
|
Loading…
Reference in a new issue