This commit is contained in:
Freddy 2013-09-26 17:26:59 -07:00
commit 462d0b90c1
11 changed files with 686 additions and 272 deletions

View 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;
}

View file

@ -0,0 +1,67 @@
#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) {
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_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 );
for(i = 0; i < gl_VerticesIn; i++) {
corner = gl_PositionIn[i];
scale = voxelSize[i];
faceOfVoxel(corner, scale, bottomFace, gl_FrontColorIn[i]);
faceOfVoxel(corner, scale, topFace, gl_FrontColorIn[i]);
faceOfVoxel(corner, scale, rightFace, gl_FrontColorIn[i]);
faceOfVoxel(corner, scale, leftFace, gl_FrontColorIn[i]);
faceOfVoxel(corner, scale, frontFace, gl_FrontColorIn[i]);
faceOfVoxel(corner, scale, backFace, gl_FrontColorIn[i]);
}
}

View file

@ -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:
@ -1518,7 +1521,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 +1541,7 @@ void Application::init() {
_glowEffect.init();
_ambientOcclusionEffect.init();
_voxelShader.init();
_handControl.setScreenDimensions(_glWidget->width(), _glWidget->height());
@ -1569,9 +1572,13 @@ 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.init();
Avatar::sendAvatarURLsMessage(_myAvatar.getVoxels()->getVoxelURL(), _myAvatar.getHead().getBlendFace().getModelURL());
_palette.init(_glWidget->width(), _glWidget->height());
@ -2565,7 +2572,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();) {
@ -2810,7 +2817,10 @@ 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("");

View file

@ -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"
@ -144,6 +145,8 @@ public:
virtual void nodeAdded(Node* node);
virtual void nodeKilled(Node* node);
virtual void packetSentNotification(ssize_t length);
VoxelShader& getVoxelShader() { return _voxelShader; }
public slots:
void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data);
@ -346,6 +349,7 @@ private:
GlowEffect _glowEffect;
AmbientOcclusionEffect _ambientOcclusionEffect;
VoxelShader _voxelShader;
#ifndef _WIN32
Audio _audio;

View file

@ -49,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();
@ -189,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);
@ -242,50 +229,120 @@ 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()));
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,
@ -293,12 +350,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);
@ -338,18 +389,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,
@ -362,32 +401,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);
@ -407,47 +435,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);
@ -469,6 +488,7 @@ void Menu::loadSettings(QSettings* settings) {
_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
@ -492,6 +512,7 @@ void Menu::saveSettings(QSettings* settings) {
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);
@ -739,9 +760,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);
@ -773,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()));
@ -785,8 +813,6 @@ void Menu::editPreferences() {
return;
}
updateDSHostname(domainServerLineEdit->text());
QUrl avatarVoxelURL(avatarURL->text());
applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL);
@ -798,6 +824,8 @@ void Menu::editPreferences() {
applicationInstance->getAvatar()->getHead().setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum());
_gyroCameraSensitivity = gyroCameraSensitivity->value();
_maxVoxels = maxVoxels->value();
applicationInstance->getVoxels()->setMaxVoxels(_maxVoxels);
applicationInstance->getAvatar()->setLeanScale(leanScale->value());
@ -997,3 +1025,8 @@ void Menu::updateFrustumRenderModeAction() {
break;
}
}
void Menu::switchVoxelShader() {
Application::getInstance()->getVoxels()->setUseVoxelShader(isOptionChecked(MenuOption::UseVoxelShader));
}

View file

@ -54,6 +54,8 @@ public:
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 +80,7 @@ private slots:
void chooseVoxelPaintColor();
void runTests();
void resetSwatchColors();
void switchVoxelShader();
private:
static Menu* _instance;
@ -115,6 +118,7 @@ private:
ViewFrustumOffset _viewFrustumOffset;
QActionGroup* _voxelModeActionsGroup;
VoxelStatsDialog* _voxelStatsDialog;
int _maxVoxels;
};
namespace MenuOption {
@ -201,9 +205,7 @@ 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 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__) */

View file

@ -74,6 +74,18 @@ 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;
_writeVoxelShaderData = NULL;
_readVoxelShaderData = NULL;
_readVerticesArray = NULL;
_writeVerticesArray = NULL;
_readColorsArray = NULL;
_writeColorsArray = NULL;
_writeVoxelDirtyArray = NULL;
_readVoxelDirtyArray = NULL;
}
void VoxelSystem::nodeDeleted(VoxelNode* node) {
@ -119,21 +131,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 +139,174 @@ VoxelSystem::~VoxelSystem() {
VoxelNode::removeDeleteHook(this);
}
void VoxelSystem::setMaxVoxels(int maxVoxels) {
pthread_mutex_lock(&_bufferWriteLock);
bool wasInitialized = _initialized;
if (wasInitialized) {
cleanupVoxelMemory();
}
_maxVoxels = maxVoxels;
if (wasInitialized) {
init();
}
pthread_mutex_unlock(&_bufferWriteLock);
}
void VoxelSystem::setUseVoxelShader(bool useVoxelShader) {
pthread_mutex_lock(&_bufferWriteLock);
bool wasInitialized = _initialized;
if (wasInitialized) {
cleanupVoxelMemory();
}
_useVoxelShader = useVoxelShader;
if (wasInitialized) {
init();
}
pthread_mutex_unlock(&_bufferWriteLock);
}
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, &_vboNormalsID);
glDeleteBuffers(1, &_vboColorsID);
glDeleteBuffers(1, &_vboIndicesID);
delete[] _readVerticesArray;
delete[] _writeVerticesArray;
delete[] _readColorsArray;
delete[] _writeColorsArray;
delete[] _writeVoxelDirtyArray;
delete[] _readVoxelDirtyArray;
}
}
_initialized = false; // no longer initialized
}
void VoxelSystem::initVoxelMemory() {
if (_useVoxelShader) {
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, _maxVoxels, indicesArray, GL_STATIC_DRAW);
glGenBuffers(1, &_vboVoxelsID);
glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID);
glBufferData(GL_ARRAY_BUFFER, _maxVoxels * sizeof(VoxelShaderVBOData), NULL, GL_DYNAMIC_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
_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
_writeVoxelShaderData = new VoxelShaderVBOData[_maxVoxels];
_readVoxelShaderData = new VoxelShaderVBOData[_maxVoxels];
} 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];
}
}
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];
}
}
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();
}
}
}
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
_tree->loadVoxelsFile(fileName, wantColorRandomizer);
setupNewVoxelsForDrawing();
@ -398,18 +564,24 @@ 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 {
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 * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes);
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
memcpy(readColorsAt, writeColorsAt, segmentSizeBytes);
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);
}
}
void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) {
@ -532,11 +704,23 @@ 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) {
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 {
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];
}
}
}
@ -563,86 +747,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 +820,27 @@ 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 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);
}
}
void VoxelSystem::render(bool texture) {
@ -734,43 +850,74 @@ 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_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
glNormalPointer(GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
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);
// 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);
glDisable(GL_CULL_FACE);
glDisable(GL_CULL_FACE);
removeScaleAndReleaseProgram(texture);
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_NORMAL_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);
// bind with 0 to switch back to normal operation
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
pthread_mutex_unlock(&_bufferWriteLock);
}
@ -1203,7 +1350,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 +1365,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 +1440,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);

View file

@ -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,10 @@ 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; }
long int getVoxelsCreated();
long int getVoxelsColored();
long int getVoxelsBytesRead();
@ -190,6 +203,16 @@ private:
uint64_t _lastViewCulling;
int _lastViewCullingElapsed;
bool getUseVoxelShader();
void initVoxelMemory();
void cleanupVoxelMemory();
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;

View 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;
}
}

View 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__) */

View file

@ -32,10 +32,10 @@ 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;
typedef unsigned long int glBufferIndex;