This commit is contained in:
Andrzej Kapolka 2013-09-30 13:22:59 -07:00
commit 5dc7b64c03
16 changed files with 422 additions and 180 deletions

View file

@ -84,7 +84,7 @@ and features are available via menus in the Interface application.
Other components Other components
======== ========
voxel-server, animation-server, audio-mixer, avatar-mixer, domain-server, assignment-client, animation-server, domain-server,
pairing-server and space-server are architectural components that will allow pairing-server and space-server are architectural components that will allow
you to run the full stack of the virtual world should you choose to. you to run the full stack of the virtual world should you choose to.

View file

@ -16,7 +16,10 @@
#include "Agent.h" #include "Agent.h"
#include "voxels/VoxelScriptingInterface.h" #include "voxels/VoxelScriptingInterface.h"
Agent::Agent(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) { Agent::Agent(const unsigned char* dataBuffer, int numBytes) :
Assignment(dataBuffer, numBytes),
_shouldStop(false)
{
} }

View file

@ -26,14 +26,17 @@ const int VERTICES_PER_FACE = 4;
const int COORD_PER_VERTEX = 3; const int COORD_PER_VERTEX = 3;
const int COORD_PER_FACE = COORD_PER_VERTEX * VERTICES_PER_FACE; const int COORD_PER_FACE = COORD_PER_VERTEX * VERTICES_PER_FACE;
void faceOfVoxel(vec4 corner, float scale, float[COORD_PER_FACE] facePoints, vec4 color) { void faceOfVoxel(vec4 corner, float scale, float[COORD_PER_FACE] facePoints, vec4 color, vec4 normal) {
for (int v = 0; v < VERTICES_PER_FACE; v++ ) { for (int v = 0; v < VERTICES_PER_FACE; v++ ) {
vec4 vertex = corner; vec4 vertex = corner;
for (int c = 0; c < COORD_PER_VERTEX; c++ ) { for (int c = 0; c < COORD_PER_VERTEX; c++ ) {
int cIndex = c + (v * COORD_PER_VERTEX); int cIndex = c + (v * COORD_PER_VERTEX);
vertex[c] += (facePoints[cIndex] * scale); vertex[c] += (facePoints[cIndex] * scale);
} }
gl_FrontColor = color;
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; gl_Position = gl_ModelViewProjectionMatrix * vertex;
EmitVertex(); EmitVertex();
} }
@ -54,14 +57,21 @@ void main() {
float frontFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 ); 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 ); 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++) { for(i = 0; i < gl_VerticesIn; i++) {
corner = gl_PositionIn[i]; corner = gl_PositionIn[i];
scale = voxelSize[i]; scale = voxelSize[i];
faceOfVoxel(corner, scale, bottomFace, gl_FrontColorIn[i]); faceOfVoxel(corner, scale, bottomFace, gl_FrontColorIn[i], bottomNormal);
faceOfVoxel(corner, scale, topFace, gl_FrontColorIn[i]); faceOfVoxel(corner, scale, topFace, gl_FrontColorIn[i], topNormal );
faceOfVoxel(corner, scale, rightFace, gl_FrontColorIn[i]); faceOfVoxel(corner, scale, rightFace, gl_FrontColorIn[i], rightNormal );
faceOfVoxel(corner, scale, leftFace, gl_FrontColorIn[i]); faceOfVoxel(corner, scale, leftFace, gl_FrontColorIn[i], leftNormal );
faceOfVoxel(corner, scale, frontFace, gl_FrontColorIn[i]); faceOfVoxel(corner, scale, frontFace, gl_FrontColorIn[i], frontNormal );
faceOfVoxel(corner, scale, backFace, gl_FrontColorIn[i]); faceOfVoxel(corner, scale, backFace, gl_FrontColorIn[i], backNormal );
} }
} }

View file

@ -151,6 +151,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
NodeList::getInstance()->addHook(&_voxels); NodeList::getInstance()->addHook(&_voxels);
NodeList::getInstance()->addHook(this); NodeList::getInstance()->addHook(this);
NodeList::getInstance()->addDomainListener(this);
// network receive thread and voxel parsing thread are both controlled by the --nonblocking command line // network receive thread and voxel parsing thread are both controlled by the --nonblocking command line
@ -231,6 +232,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
Application::~Application() { Application::~Application() {
NodeList::getInstance()->removeHook(&_voxels); NodeList::getInstance()->removeHook(&_voxels);
NodeList::getInstance()->removeHook(this); NodeList::getInstance()->removeHook(this);
NodeList::getInstance()->removeDomainListener(this);
_sharedVoxelSystem.changeTree(new VoxelTree); _sharedVoxelSystem.changeTree(new VoxelTree);
@ -309,8 +311,6 @@ void Application::initializeGL() {
char title[50]; char title[50];
sprintf(title, "Interface: %4.2f seconds\n", startupTime); sprintf(title, "Interface: %4.2f seconds\n", startupTime);
qDebug("%s", title); qDebug("%s", title);
_window->setWindowTitle(title);
const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time"; const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
// ask the Logstash class to record the startup time // ask the Logstash class to record the startup time
@ -1001,6 +1001,17 @@ void Application::mousePressEvent(QMouseEvent* event) {
_audio.startCollisionSound(1.0, frequency, 0.0, HOVER_VOXEL_DECAY); _audio.startCollisionSound(1.0, frequency, 0.0, HOVER_VOXEL_DECAY);
_isHoverVoxelSounding = true; _isHoverVoxelSounding = true;
const float PERCENTAGE_TO_MOVE_TOWARD = 0.90f;
glm::vec3 newTarget = getMouseVoxelWorldCoordinates(_hoverVoxel);
glm::vec3 myPosition = _myAvatar.getPosition();
// If there is not an action tool set (add, delete, color), move to this voxel
if (!(Menu::getInstance()->isOptionChecked(MenuOption::VoxelAddMode) ||
Menu::getInstance()->isOptionChecked(MenuOption::VoxelDeleteMode) ||
Menu::getInstance()->isOptionChecked(MenuOption::VoxelColorMode))) {
_myAvatar.setMoveTarget(myPosition + (newTarget - myPosition) * PERCENTAGE_TO_MOVE_TOWARD);
}
} }
} else if (event->button() == Qt::RightButton && Menu::getInstance()->isVoxelModeActionChecked()) { } else if (event->button() == Qt::RightButton && Menu::getInstance()->isVoxelModeActionChecked()) {
@ -1577,7 +1588,6 @@ void Application::init() {
// Set up VoxelSystem after loading preferences so we can get the desired max voxel count // Set up VoxelSystem after loading preferences so we can get the desired max voxel count
_voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels()); _voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels());
_voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader)); _voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader));
_voxels.setUseByteNormals(Menu::getInstance()->isOptionChecked(MenuOption::UseByteNormals));
_voxels.init(); _voxels.init();
@ -2827,28 +2837,36 @@ void Application::displayStats() {
voxelStats << "Voxels Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K " << voxelStats << "Voxels Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K " <<
"Updated: " << _voxels.getVoxelsUpdated()/1000.f << "K " << "Updated: " << _voxels.getVoxelsUpdated()/1000.f << "K " <<
"Max: " << _voxels.getMaxVoxels()/1000.f << "K "; "Max: " << _voxels.getMaxVoxels()/1000.f << "K ";
drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str("");
voxelStats << "Voxels Memory RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB " <<
"VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB ";
if (_voxels.hasVoxelMemoryUsageGPU()) {
voxelStats << "GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB ";
}
drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str(""); voxelStats.str("");
char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS); char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS);
voxelStats << "Voxels Sent from Server: " << voxelDetails; voxelStats << "Voxels Sent from Server: " << voxelDetails;
drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str(""); voxelStats.str("");
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ELAPSED); voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ELAPSED);
voxelStats << "Scene Send Time from Server: " << voxelDetails; voxelStats << "Scene Send Time from Server: " << voxelDetails;
drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); drawtext(10, statsVerticalOffset + 290, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str(""); voxelStats.str("");
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ENCODE); voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ENCODE);
voxelStats << "Encode Time on Server: " << voxelDetails; voxelStats << "Encode Time on Server: " << voxelDetails;
drawtext(10, statsVerticalOffset + 290, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str(""); voxelStats.str("");
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_MODE); voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_MODE);
voxelStats << "Sending Mode: " << voxelDetails; voxelStats << "Sending Mode: " << voxelDetails;
drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
char avatarMixerStats[200]; char avatarMixerStats[200];
@ -2861,7 +2879,7 @@ void Application::displayStats() {
sprintf(avatarMixerStats, "No Avatar Mixer"); sprintf(avatarMixerStats, "No Avatar Mixer");
} }
drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, avatarMixerStats); drawtext(10, statsVerticalOffset + 350, 0.10f, 0, 1.0, 0, avatarMixerStats);
drawtext(10, statsVerticalOffset + 450, 0.10f, 0, 1.0, 0, (char *)LeapManager::statusString().c_str()); drawtext(10, statsVerticalOffset + 450, 0.10f, 0, 1.0, 0, (char *)LeapManager::statusString().c_str());
if (_perfStatsOn) { if (_perfStatsOn) {
@ -3414,6 +3432,11 @@ void Application::attachNewHeadToNode(Node* newNode) {
} }
} }
void Application::domainChanged(QString domain) {
qDebug("Application title set to: %s.\n", domain.toStdString().c_str());
_window->setWindowTitle(domain);
}
void Application::nodeAdded(Node* node) { void Application::nodeAdded(Node* node) {
} }

View file

@ -77,7 +77,7 @@ static const float NODE_KILLED_RED = 1.0f;
static const float NODE_KILLED_GREEN = 0.0f; static const float NODE_KILLED_GREEN = 0.0f;
static const float NODE_KILLED_BLUE = 0.0f; static const float NODE_KILLED_BLUE = 0.0f;
class Application : public QApplication, public NodeListHook, public PacketSenderNotify { class Application : public QApplication, public NodeListHook, public PacketSenderNotify, public DomainChangeListener {
Q_OBJECT Q_OBJECT
friend class VoxelPacketProcessor; friend class VoxelPacketProcessor;
@ -146,6 +146,8 @@ public:
virtual void nodeKilled(Node* node); virtual void nodeKilled(Node* node);
virtual void packetSentNotification(ssize_t length); virtual void packetSentNotification(ssize_t length);
virtual void domainChanged(QString domain);
VoxelShader& getVoxelShader() { return _voxelShader; } VoxelShader& getVoxelShader() { return _voxelShader; }
public slots: public slots:

View file

@ -254,9 +254,6 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0, addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0,
false, this, SLOT(switchVoxelShader())); false, this, SLOT(switchVoxelShader()));
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseByteNormals, 0,
false, Application::getInstance()->getVoxels(), SLOT(setUseByteNormals(bool)));
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true);

View file

@ -205,6 +205,7 @@ namespace MenuOption {
const QString Quit = "Quit"; const QString Quit = "Quit";
const QString UseVoxelShader = "Use Voxel Shader"; const QString UseVoxelShader = "Use Voxel Shader";
const QString UseByteNormals = "Use Byte Normals"; const QString UseByteNormals = "Use Byte Normals";
const QString UseGlobalNormals = "Use Global Normals";
const QString Voxels = "Voxels"; const QString Voxels = "Voxels";
const QString VoxelAddMode = "Add Voxel Mode"; const QString VoxelAddMode = "Add Voxel Mode";
const QString VoxelColorMode = "Color Voxel Mode"; const QString VoxelColorMode = "Color Voxel Mode";

View file

@ -33,11 +33,13 @@
#include "VoxelConstants.h" #include "VoxelConstants.h"
#include "VoxelSystem.h" #include "VoxelSystem.h"
float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, float identityVerticesGlobalNormals[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 };
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1,
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 };
GLbyte identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-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, 0,0,+1, 0,0,+1, 0,0,+1, 0,0,+1,
0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0, 0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0,
0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0, 0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0,
@ -51,6 +53,13 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z-
10,11,15, 10,15,14, // Y+ 10,11,15, 10,15,14, // Y+
4,5,6, 4,6,7 }; // Z+ 4,5,6, 4,6,7 }; // Z+
GLubyte identityIndicesTop[] = { 2, 3, 7, 2, 7, 6 };
GLubyte identityIndicesBottom[] = { 0, 1, 5, 0, 5, 4 };
GLubyte identityIndicesLeft[] = { 0, 7, 3, 0, 4, 7 };
GLubyte identityIndicesRight[] = { 1, 2, 6, 1, 6, 5 };
GLubyte identityIndicesFront[] = { 0, 2, 1, 0, 3, 2 };
GLubyte identityIndicesBack[] = { 4, 5, 6, 4, 6, 7 };
VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
: NodeData(NULL), : NodeData(NULL),
_treeScale(treeScale), _treeScale(treeScale),
@ -76,8 +85,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int))); connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int)));
_useVoxelShader = false; _useVoxelShader = false;
_useByteNormals = false;
_writeVoxelShaderData = NULL; _writeVoxelShaderData = NULL;
_readVoxelShaderData = NULL; _readVoxelShaderData = NULL;
@ -141,24 +149,11 @@ VoxelSystem::~VoxelSystem() {
VoxelNode::removeDeleteHook(this); VoxelNode::removeDeleteHook(this);
} }
void VoxelSystem::setUseByteNormals(bool useByteNormals) {
pthread_mutex_lock(&_bufferWriteLock);
bool wasInitialized = _initialized;
if (wasInitialized) {
cleanupVoxelMemory();
}
_useByteNormals = useByteNormals;
if (wasInitialized) {
init();
}
pthread_mutex_unlock(&_bufferWriteLock);
}
void VoxelSystem::setMaxVoxels(int maxVoxels) { void VoxelSystem::setMaxVoxels(int maxVoxels) {
pthread_mutex_lock(&_bufferWriteLock); pthread_mutex_lock(&_bufferWriteLock);
bool wasInitialized = _initialized; bool wasInitialized = _initialized;
if (wasInitialized) { if (wasInitialized) {
clearAllNodesBufferIndex();
cleanupVoxelMemory(); cleanupVoxelMemory();
} }
_maxVoxels = maxVoxels; _maxVoxels = maxVoxels;
@ -166,12 +161,17 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) {
init(); init();
} }
pthread_mutex_unlock(&_bufferWriteLock); pthread_mutex_unlock(&_bufferWriteLock);
if (wasInitialized) {
forceRedrawEntireTree();
}
} }
void VoxelSystem::setUseVoxelShader(bool useVoxelShader) { void VoxelSystem::setUseVoxelShader(bool useVoxelShader) {
pthread_mutex_lock(&_bufferWriteLock); pthread_mutex_lock(&_bufferWriteLock);
bool wasInitialized = _initialized; bool wasInitialized = _initialized;
if (wasInitialized) { if (wasInitialized) {
clearAllNodesBufferIndex();
cleanupVoxelMemory(); cleanupVoxelMemory();
} }
_useVoxelShader = useVoxelShader; _useVoxelShader = useVoxelShader;
@ -179,6 +179,10 @@ void VoxelSystem::setUseVoxelShader(bool useVoxelShader) {
init(); init();
} }
pthread_mutex_unlock(&_bufferWriteLock); pthread_mutex_unlock(&_bufferWriteLock);
if (wasInitialized) {
forceRedrawEntireTree();
}
} }
void VoxelSystem::cleanupVoxelMemory() { void VoxelSystem::cleanupVoxelMemory() {
@ -193,22 +197,58 @@ void VoxelSystem::cleanupVoxelMemory() {
} else { } else {
// Destroy glBuffers // Destroy glBuffers
glDeleteBuffers(1, &_vboVerticesID); glDeleteBuffers(1, &_vboVerticesID);
glDeleteBuffers(1, &_vboNormalsID);
glDeleteBuffers(1, &_vboColorsID); glDeleteBuffers(1, &_vboColorsID);
glDeleteBuffers(1, &_vboIndicesID);
glDeleteBuffers(1, &_vboIndicesTop);
glDeleteBuffers(1, &_vboIndicesBottom);
glDeleteBuffers(1, &_vboIndicesLeft);
glDeleteBuffers(1, &_vboIndicesRight);
glDeleteBuffers(1, &_vboIndicesFront);
glDeleteBuffers(1, &_vboIndicesBack);
delete[] _readVerticesArray; delete[] _readVerticesArray;
delete[] _writeVerticesArray; delete[] _writeVerticesArray;
delete[] _readColorsArray; delete[] _readColorsArray;
delete[] _writeColorsArray; delete[] _writeColorsArray;
delete[] _writeVoxelDirtyArray;
delete[] _readVoxelDirtyArray;
} }
delete[] _writeVoxelDirtyArray;
delete[] _readVoxelDirtyArray;
} }
_initialized = false; // no longer initialized _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() { void VoxelSystem::initVoxelMemory() {
_initialMemoryUsageGPU = getFreeMemoryGPU();
_memoryUsageRAM = 0;
_memoryUsageVBO = 0; // our VBO allocations as we know them
if (_useVoxelShader) { if (_useVoxelShader) {
qDebug("Using Voxel Shader...\n"); qDebug("Using Voxel Shader...\n");
GLuint* indicesArray = new GLuint[_maxVoxels]; GLuint* indicesArray = new GLuint[_maxVoxels];
@ -222,12 +262,13 @@ void VoxelSystem::initVoxelMemory() {
// bind the indices VBO to the actual indices array // bind the indices VBO to the actual indices array
glGenBuffers(1, &_vboVoxelsIndicesID); glGenBuffers(1, &_vboVoxelsIndicesID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _maxVoxels, indicesArray, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * _maxVoxels, indicesArray, GL_STATIC_DRAW);
_memoryUsageVBO += sizeof(GLuint) * _maxVoxels;
glGenBuffers(1, &_vboVoxelsID); glGenBuffers(1, &_vboVoxelsID);
glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID); glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID);
glBufferData(GL_ARRAY_BUFFER, _maxVoxels * sizeof(VoxelShaderVBOData), NULL, GL_DYNAMIC_DRAW); 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 the indices and normals arrays that are no longer needed
delete[] indicesArray; delete[] indicesArray;
@ -235,106 +276,62 @@ void VoxelSystem::initVoxelMemory() {
// we will track individual dirty sections with these arrays of bools // we will track individual dirty sections with these arrays of bools
_writeVoxelDirtyArray = new bool[_maxVoxels]; _writeVoxelDirtyArray = new bool[_maxVoxels];
memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
_memoryUsageRAM += (_maxVoxels * sizeof(bool));
_readVoxelDirtyArray = new bool[_maxVoxels]; _readVoxelDirtyArray = new bool[_maxVoxels];
memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
_memoryUsageRAM += (_maxVoxels * sizeof(bool));
// prep the data structures for incoming voxel data // prep the data structures for incoming voxel data
_writeVoxelShaderData = new VoxelShaderVBOData[_maxVoxels]; _writeVoxelShaderData = new VoxelShaderVBOData[_maxVoxels];
_memoryUsageRAM += (sizeof(VoxelShaderVBOData) * _maxVoxels);
_readVoxelShaderData = new VoxelShaderVBOData[_maxVoxels]; _readVoxelShaderData = new VoxelShaderVBOData[_maxVoxels];
_memoryUsageRAM += (sizeof(VoxelShaderVBOData) * _maxVoxels);
} else { } else {
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];
}
}
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];
}
}
// 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);
// 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);
// delete the indices and normals arrays that are no longer needed
delete[] normalsArray;
}
// 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);
// Depending on if we're using per vertex normals, we will need more or less vertex points per voxel
int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL;
glGenBuffers(1, &_vboVerticesID); glGenBuffers(1, &_vboVerticesID);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);
_memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels;
// VBO for colorsArray // VBO for colorsArray
glGenBuffers(1, &_vboColorsID); glGenBuffers(1, &_vboColorsID);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);
_memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels;
// 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;
// we will track individual dirty sections with these arrays of bools // we will track individual dirty sections with these arrays of bools
_writeVoxelDirtyArray = new bool[_maxVoxels]; _writeVoxelDirtyArray = new bool[_maxVoxels];
memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
_memoryUsageRAM += (sizeof(bool) * _maxVoxels);
_readVoxelDirtyArray = new bool[_maxVoxels]; _readVoxelDirtyArray = new bool[_maxVoxels];
memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
_memoryUsageRAM += (sizeof(bool) * _maxVoxels);
// prep the data structures for incoming voxel data // prep the data structures for incoming voxel data
_writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; _writeVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels];
_readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; _memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels);
_readVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels];
_memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels);
_writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; _writeColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels];
_readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _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 // create our simple fragment shader if we're the first system to init
@ -614,16 +611,19 @@ void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart,
void* writeDataAt = &_writeVoxelShaderData[segmentStart]; void* writeDataAt = &_writeVoxelShaderData[segmentStart];
memcpy(readDataAt, writeDataAt, segmentSizeBytes); memcpy(readDataAt, writeDataAt, segmentSizeBytes);
} else { } else {
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL;
GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); 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); memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes);
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte);
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte);
GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); GLubyte* readColorsAt = _readColorsArray + (segmentStart * vertexPointsPerVoxel);
GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * vertexPointsPerVoxel);
memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); memcpy(readColorsAt, writeColorsAt, segmentSizeBytes);
} }
} }
@ -750,20 +750,25 @@ void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& s
float voxelScale, const nodeColor& color) { float voxelScale, const nodeColor& color) {
if (_useVoxelShader) { if (_useVoxelShader) {
VoxelShaderVBOData* writeVerticesAt = &_writeVoxelShaderData[nodeIndex]; if (_writeVoxelShaderData) {
writeVerticesAt->x = startVertex.x * TREE_SCALE; VoxelShaderVBOData* writeVerticesAt = &_writeVoxelShaderData[nodeIndex];
writeVerticesAt->y = startVertex.y * TREE_SCALE; writeVerticesAt->x = startVertex.x * TREE_SCALE;
writeVerticesAt->z = startVertex.z * TREE_SCALE; writeVerticesAt->y = startVertex.y * TREE_SCALE;
writeVerticesAt->s = voxelScale * TREE_SCALE; writeVerticesAt->z = startVertex.z * TREE_SCALE;
writeVerticesAt->r = color[RED_INDEX]; writeVerticesAt->s = voxelScale * TREE_SCALE;
writeVerticesAt->g = color[GREEN_INDEX]; writeVerticesAt->r = color[RED_INDEX];
writeVerticesAt->b = color[BLUE_INDEX]; writeVerticesAt->g = color[GREEN_INDEX];
writeVerticesAt->b = color[BLUE_INDEX];
}
} else { } else {
for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { if (_writeVerticesArray && _writeColorsArray) {
GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL;
GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); for (int j = 0; j < vertexPointsPerVoxel; j++ ) {
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * vertexPointsPerVoxel);
*(writeColorsAt +j) = color[j % 3]; GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * vertexPointsPerVoxel);
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVerticesGlobalNormals[j] * voxelScale);
*(writeColorsAt +j) = color[j % 3];
}
} }
} }
} }
@ -873,15 +878,16 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg
glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID); glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
} else { } else {
int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL;
int segmentLength = (segmentEnd - segmentStart) + 1; int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat);
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat);
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * vertexPointsPerVoxel);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte);
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte);
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); GLubyte* readColorsFrom = _readColorsArray + (segmentStart * vertexPointsPerVoxel);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
} }
@ -927,15 +933,11 @@ void VoxelSystem::render(bool texture) {
} else { } else {
// tell OpenGL where to find vertex and color information // tell OpenGL where to find vertex and color information
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glVertexPointer(3, GL_FLOAT, 0, 0); glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
glNormalPointer((_useByteNormals ? GL_BYTE : GL_FLOAT), 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
@ -944,10 +946,38 @@ void VoxelSystem::render(bool texture) {
// for performance, enable backface culling // for performance, enable backface culling
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
// draw the number of voxels we have // draw voxels in 6 passes
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, glNormal3f(0,1.0f,0);
36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
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); glDisable(GL_CULL_FACE);
@ -955,7 +985,6 @@ void VoxelSystem::render(bool texture) {
// deactivate vertex and color arrays after drawing // deactivate vertex and color arrays after drawing
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_COLOR_ARRAY);
// bind with 0 to switch back to normal operation // bind with 0 to switch back to normal operation
@ -995,6 +1024,34 @@ void VoxelSystem::killLocalVoxels() {
} }
bool VoxelSystem::clearAllNodesBufferIndexOperation(VoxelNode* node, void* extraData) {
_nodeCount++;
node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN);
return true;
}
void VoxelSystem::clearAllNodesBufferIndex() {
_nodeCount = 0;
_tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation);
qDebug("clearing buffer index of %d nodes\n", _nodeCount);
_tree->setDirtyBit();
setupNewVoxelsForDrawing();
}
bool VoxelSystem::forceRedrawEntireTreeOperation(VoxelNode* node, void* extraData) {
_nodeCount++;
node->setDirtyBit();
return true;
}
void VoxelSystem::forceRedrawEntireTree() {
_nodeCount = 0;
_tree->recurseTreeWithOperation(forceRedrawEntireTreeOperation);
qDebug("forcing redraw of %d nodes\n", _nodeCount);
_tree->setDirtyBit();
setupNewVoxelsForDrawing();
}
bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) { bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) {
_nodeCount++; _nodeCount++;
if (node->isColored()) { if (node->isColored()) {
@ -1852,3 +1909,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);
}

View file

@ -69,6 +69,10 @@ public:
void setMaxVoxels(int maxVoxels); void setMaxVoxels(int maxVoxels);
long int getMaxVoxels() const { return _maxVoxels; } long int getMaxVoxels() const { return _maxVoxels; }
unsigned long getVoxelMemoryUsageRAM() const { return _memoryUsageRAM; }
unsigned long getVoxelMemoryUsageVBO() const { return _memoryUsageVBO; }
bool hasVoxelMemoryUsageGPU() const { return _hasMemoryUsageGPU; }
unsigned long getVoxelMemoryUsageGPU();
long int getVoxelsCreated(); long int getVoxelsCreated();
long int getVoxelsColored(); long int getVoxelsColored();
long int getVoxelsBytesRead(); long int getVoxelsBytesRead();
@ -126,9 +130,10 @@ public slots:
void falseColorizeOccluded(); void falseColorizeOccluded();
void falseColorizeOccludedV2(); void falseColorizeOccludedV2();
void falseColorizeBySource(); void falseColorizeBySource();
void forceRedrawEntireTree();
void clearAllNodesBufferIndex();
void cancelImport(); void cancelImport();
void setUseByteNormals(bool useByteNormals);
protected: protected:
float _treeScale; float _treeScale;
@ -172,6 +177,8 @@ private:
static bool falseColorizeOccludedV2Operation(VoxelNode* node, void* extraData); static bool falseColorizeOccludedV2Operation(VoxelNode* node, void* extraData);
static bool falseColorizeBySourceOperation(VoxelNode* node, void* extraData); static bool falseColorizeBySourceOperation(VoxelNode* node, void* extraData);
static bool killSourceVoxelsOperation(VoxelNode* node, void* extraData); static bool killSourceVoxelsOperation(VoxelNode* node, void* extraData);
static bool forceRedrawEntireTreeOperation(VoxelNode* node, void* extraData);
static bool clearAllNodesBufferIndexOperation(VoxelNode* node, void* extraData);
int updateNodeInArraysAsFullVBO(VoxelNode* node); int updateNodeInArraysAsFullVBO(VoxelNode* node);
int updateNodeInArraysAsPartialVBO(VoxelNode* node); int updateNodeInArraysAsPartialVBO(VoxelNode* node);
@ -181,6 +188,8 @@ private:
void updateVBOs(); void updateVBOs();
unsigned long getFreeMemoryGPU();
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
static float _maxDistance; static float _maxDistance;
static float _minDistance; static float _minDistance;
@ -207,8 +216,6 @@ private:
void initVoxelMemory(); void initVoxelMemory();
void cleanupVoxelMemory(); void cleanupVoxelMemory();
bool _useByteNormals;
bool _useVoxelShader; bool _useVoxelShader;
GLuint _vboVoxelsID; /// when using voxel shader, we'll use this VBO 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 GLuint _vboVoxelsIndicesID; /// when using voxel shader, we'll use this VBO for our indexes
@ -216,9 +223,15 @@ private:
VoxelShaderVBOData* _readVoxelShaderData; VoxelShaderVBOData* _readVoxelShaderData;
GLuint _vboVerticesID; GLuint _vboVerticesID;
GLuint _vboNormalsID;
GLuint _vboColorsID; GLuint _vboColorsID;
GLuint _vboIndicesID;
GLuint _vboIndicesTop;
GLuint _vboIndicesBottom;
GLuint _vboIndicesLeft;
GLuint _vboIndicesRight;
GLuint _vboIndicesFront;
GLuint _vboIndicesBack;
pthread_mutex_t _bufferWriteLock; pthread_mutex_t _bufferWriteLock;
pthread_mutex_t _treeLock; pthread_mutex_t _treeLock;
@ -226,6 +239,8 @@ private:
ViewFrustum _lastStableViewFrustum; ViewFrustum _lastStableViewFrustum;
ViewFrustum* _viewFrustum; ViewFrustum* _viewFrustum;
void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]);
int newTreeToArrays(VoxelNode *currentNode); int newTreeToArrays(VoxelNode *currentNode);
void cleanupRemovedVoxels(); void cleanupRemovedVoxels();
@ -249,6 +264,10 @@ private:
int _dataSourceID; int _dataSourceID;
int _voxelServerCount; int _voxelServerCount;
unsigned long _memoryUsageRAM;
unsigned long _memoryUsageVBO;
unsigned long _initialMemoryUsageGPU;
bool _hasMemoryUsageGPU;
}; };
#endif #endif

View file

@ -50,7 +50,9 @@ MyAvatar::MyAvatar(Node* owningNode) :
_lastCollisionPosition(0, 0, 0), _lastCollisionPosition(0, 0, 0),
_speedBrakes(false), _speedBrakes(false),
_isThrustOn(false), _isThrustOn(false),
_thrustMultiplier(1.0f) _thrustMultiplier(1.0f),
_moveTarget(0,0,0),
_moveTargetStepCounter(0)
{ {
for (int i = 0; i < MAX_DRIVE_KEYS; i++) { for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
_driveKeys[i] = false; _driveKeys[i] = false;
@ -64,6 +66,11 @@ void MyAvatar::reset() {
_hand.reset(); _hand.reset();
} }
void MyAvatar::setMoveTarget(const glm::vec3 moveTarget) {
_moveTarget = moveTarget;
_moveTargetStepCounter = 0;
}
void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) { void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
glm::quat orientation = getOrientation(); glm::quat orientation = getOrientation();
@ -165,8 +172,10 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) { if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) {
_velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime); _velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime);
} }
// Only collide if we are not moving to a target
if (_isCollisionsOn && (glm::length(_moveTarget) < EPSILON)) {
if (_isCollisionsOn) {
Camera* myCamera = Application::getInstance()->getCamera(); Camera* myCamera = Application::getInstance()->getCamera();
if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) { if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) {
@ -211,7 +220,7 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
// Damp avatar velocity // Damp avatar velocity
const float LINEAR_DAMPING_STRENGTH = 0.5f; const float LINEAR_DAMPING_STRENGTH = 0.5f;
const float SPEED_BRAKE_POWER = _scale * 10.0f; const float SPEED_BRAKE_POWER = _scale * 10.0f;
const float SQUARED_DAMPING_STRENGTH = 0.0f; const float SQUARED_DAMPING_STRENGTH = 0.007f;
float linearDamping = LINEAR_DAMPING_STRENGTH; float linearDamping = LINEAR_DAMPING_STRENGTH;
const float AVATAR_DAMPING_FACTOR = 120.f; const float AVATAR_DAMPING_FACTOR = 120.f;
@ -225,12 +234,15 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
} }
// pitch and roll the body as a function of forward speed and turning delta // pitch and roll the body as a function of forward speed and turning delta
const float BODY_PITCH_WHILE_WALKING = -20.0; const float HIGH_VELOCITY = 10.f;
const float BODY_ROLL_WHILE_TURNING = 0.2; if (glm::length(_velocity) < HIGH_VELOCITY) {
float forwardComponentOfVelocity = glm::dot(getBodyFrontDirection(), _velocity); const float BODY_PITCH_WHILE_WALKING = -20.0;
orientation = orientation * glm::quat(glm::radians(glm::vec3( const float BODY_ROLL_WHILE_TURNING = 0.2;
BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity, 0.0f, float forwardComponentOfVelocity = glm::dot(getBodyFrontDirection(), _velocity);
BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta))); orientation = orientation * glm::quat(glm::radians(glm::vec3(
BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity, 0.0f,
BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta)));
}
// these forces keep the body upright... // these forces keep the body upright...
const float BODY_UPRIGHT_FORCE = _scale * 10.0; const float BODY_UPRIGHT_FORCE = _scale * 10.0;
@ -321,7 +333,21 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
const float MOVING_SPEED_THRESHOLD = 0.01f; const float MOVING_SPEED_THRESHOLD = 0.01f;
_moving = _speed > MOVING_SPEED_THRESHOLD; _moving = _speed > MOVING_SPEED_THRESHOLD;
// update position by velocity, and subtract the change added earlier for gravity // If a move target is set, update position explicitly
const float MOVE_FINISHED_TOLERANCE = 0.1f;
const float MOVE_SPEED_FACTOR = 2.f;
const int MOVE_TARGET_MAX_STEPS = 250;
if ((glm::length(_moveTarget) > EPSILON) && (_moveTargetStepCounter < MOVE_TARGET_MAX_STEPS)) {
if (glm::length(_position - _moveTarget) > MOVE_FINISHED_TOLERANCE) {
_position += (_moveTarget - _position) * (deltaTime * MOVE_SPEED_FACTOR);
_moveTargetStepCounter++;
} else {
// Move completed
_moveTarget = glm::vec3(0,0,0);
_moveTargetStepCounter = 0;
}
}
_position += _velocity * deltaTime; _position += _velocity * deltaTime;
// Zero thrust out now that we've added it to velocity in this frame // Zero thrust out now that we've added it to velocity in this frame
@ -648,8 +674,12 @@ void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) {
// If thrust keys are being held down, slowly increase thrust to allow reaching great speeds // If thrust keys are being held down, slowly increase thrust to allow reaching great speeds
if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) { if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) {
const float THRUST_INCREASE_RATE = 1.0; const float THRUST_INCREASE_RATE = 1.05;
_thrustMultiplier *= 1.f + deltaTime * THRUST_INCREASE_RATE; const float MAX_THRUST_MULTIPLIER = 75.0;
//printf("m = %.3f\n", _thrustMultiplier);
if (_thrustMultiplier < MAX_THRUST_MULTIPLIER) {
_thrustMultiplier *= 1.f + deltaTime * THRUST_INCREASE_RATE;
}
} else { } else {
_thrustMultiplier = 1.f; _thrustMultiplier = 1.f;
} }

View file

@ -31,6 +31,7 @@ public:
void setOrientation(const glm::quat& orientation); void setOrientation(const glm::quat& orientation);
void setNewScale(const float scale); void setNewScale(const float scale);
void setWantCollisionsOn(bool wantCollisionsOn) { _isCollisionsOn = wantCollisionsOn; } void setWantCollisionsOn(bool wantCollisionsOn) { _isCollisionsOn = wantCollisionsOn; }
void setMoveTarget(const glm::vec3 moveTarget);
// getters // getters
float getNewScale() const { return _newScale; } float getNewScale() const { return _newScale; }
@ -73,6 +74,8 @@ public:
bool _isThrustOn; bool _isThrustOn;
float _thrustMultiplier; float _thrustMultiplier;
float _collisionRadius; float _collisionRadius;
glm::vec3 _moveTarget;
int _moveTargetStepCounter;
// private methods // private methods
float getBallRenderAlpha(int ball, bool lookingInMirror) const; float getBallRenderAlpha(int ball, bool lookingInMirror) const;

View file

@ -109,6 +109,7 @@ void NodeList::setDomainHostname(const QString& domainHostname) {
// reset our _domainIP to the null address so that a lookup happens on next check in // reset our _domainIP to the null address so that a lookup happens on next check in
_domainIP.clear(); _domainIP.clear();
notifyDomainChanged();
} }
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) { void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
@ -585,6 +586,7 @@ void NodeList::loadData(QSettings *settings) {
if (domainServerHostname.size() > 0) { if (domainServerHostname.size() > 0) {
_domainHostname = domainServerHostname; _domainHostname = domainServerHostname;
notifyDomainChanged();
} }
settings->endGroup(); settings->endGroup();
@ -678,6 +680,21 @@ void NodeListIterator::skipDeadAndStopIncrement() {
} }
} }
void NodeList::addDomainListener(DomainChangeListener* listener) {
_domainListeners.push_back(listener);
QString domain = _domainHostname.isEmpty() ? _domainIP.toString() : _domainHostname;
listener->domainChanged(domain);
}
void NodeList::removeDomainListener(DomainChangeListener* listener) {
for (int i = 0; i < _domainListeners.size(); i++) {
if (_domainListeners[i] == listener) {
_domainListeners.erase(_domainListeners.begin() + i);
return;
}
}
}
void NodeList::addHook(NodeListHook* hook) { void NodeList::addHook(NodeListHook* hook) {
_hooks.push_back(hook); _hooks.push_back(hook);
} }
@ -704,3 +721,9 @@ void NodeList::notifyHooksOfKilledNode(Node* node) {
_hooks[i]->nodeKilled(node); _hooks[i]->nodeKilled(node);
} }
} }
void NodeList::notifyDomainChanged() {
for (int i = 0; i < _domainListeners.size(); i++) {
_domainListeners[i]->domainChanged(_domainHostname);
}
}

View file

@ -56,6 +56,10 @@ public:
virtual void nodeKilled(Node* node) = 0; virtual void nodeKilled(Node* node) = 0;
}; };
class DomainChangeListener {
public:
virtual void domainChanged(QString domain) = 0;
};
class NodeList { class NodeList {
public: public:
@ -136,6 +140,9 @@ public:
void notifyHooksOfAddedNode(Node* node); void notifyHooksOfAddedNode(Node* node);
void notifyHooksOfKilledNode(Node* node); void notifyHooksOfKilledNode(Node* node);
void addDomainListener(DomainChangeListener* listener);
void removeDomainListener(DomainChangeListener* listener);
private: private:
static NodeList* _sharedInstance; static NodeList* _sharedInstance;
@ -167,6 +174,11 @@ private:
void timePingReply(sockaddr *nodeAddress, unsigned char *packetData); void timePingReply(sockaddr *nodeAddress, unsigned char *packetData);
std::vector<NodeListHook*> _hooks; std::vector<NodeListHook*> _hooks;
std::vector<DomainChangeListener*> _domainListeners;
void resetDomainData(char domainField[], const char* domainData);
void notifyDomainChanged();
void domainLookup();
}; };
class NodeListIterator : public std::iterator<std::input_iterator_tag, Node> { class NodeListIterator : public std::iterator<std::input_iterator_tag, Node> {

View file

@ -443,7 +443,7 @@ void ViewFrustum::printDebugDetails() const {
glm::vec2 ViewFrustum::projectPoint(glm::vec3 point, bool& pointInView) const { glm::vec2 ViewFrustum::projectPoint(glm::vec3 point, bool& pointInView) const {
glm::vec4 pointVec4 = glm::vec4(point,1) ; glm::vec4 pointVec4 = glm::vec4(point,1);
glm::vec4 projectedPointVec4 = _ourModelViewProjectionMatrix * pointVec4; glm::vec4 projectedPointVec4 = _ourModelViewProjectionMatrix * pointVec4;
pointInView = (projectedPointVec4.w > 0); // math! If the w result is negative then the point is behind the viewer pointInView = (projectedPointVec4.w > 0); // math! If the w result is negative then the point is behind the viewer

View file

@ -38,6 +38,12 @@ const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; // xyz for each VERT
const int INDICES_PER_VOXEL = 3 * 12; // 6 sides * 2 triangles per size * 3 vertices per triangle const int INDICES_PER_VOXEL = 3 * 12; // 6 sides * 2 triangles per size * 3 vertices per triangle
const int COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * VERTICES_PER_VOXEL; const int COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * VERTICES_PER_VOXEL;
const int VERTICES_PER_FACE = 4; // 6 sides * 4 corners per side
const int INDICES_PER_FACE = 3 * 2; // 1 side * 2 triangles per size * 3 vertices per triangle
const int GLOBAL_NORMALS_VERTICES_PER_VOXEL = 8; // no need for 3 copies because they don't include normal
const int GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL = 3 * GLOBAL_NORMALS_VERTICES_PER_VOXEL;
const int GLOBAL_NORMALS_COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * GLOBAL_NORMALS_VERTICES_PER_VOXEL;
typedef unsigned long int glBufferIndex; typedef unsigned long int glBufferIndex;
const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX; const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;

View file

@ -70,6 +70,7 @@ public:
void printDebugDetails(const char* label) const; void printDebugDetails(const char* label) const;
bool isDirty() const { return _isDirty; } bool isDirty() const { return _isDirty; }
void clearDirtyBit() { _isDirty = false; } void clearDirtyBit() { _isDirty = false; }
void setDirtyBit() { _isDirty = true; }
bool hasChangedSince(uint64_t time) const { return (_lastChanged > time); } bool hasChangedSince(uint64_t time) const { return (_lastChanged > time); }
void markWithChangedTime() { _lastChanged = usecTimestampNow(); } void markWithChangedTime() { _lastChanged = usecTimestampNow(); }
uint64_t getLastChanged() const { return _lastChanged; } uint64_t getLastChanged() const { return _lastChanged; }