Merge branch 'master' of https://github.com/worklist/hifi into voxel_sending_helper

Conflicts:
	interface/src/Application.cpp
	interface/src/Application.h
This commit is contained in:
ZappoMan 2013-08-14 13:12:23 -07:00
commit f09dcfa4b7
12 changed files with 350 additions and 67 deletions

View file

@ -0,0 +1,24 @@
#version 120
//
// horizontal_blur.frag
// fragment shader
//
// Created by Andrzej Kapolka on 8/8/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
// the texture containing the original color
uniform sampler2D originalTexture;
void main(void) {
float ds = dFdx(gl_TexCoord[0].s);
gl_FragColor = (texture2D(originalTexture, gl_TexCoord[0].st + vec2(ds * -7.5, 0.0)) +
texture2D(originalTexture, gl_TexCoord[0].st + vec2(ds * -5.5, 0.0)) +
texture2D(originalTexture, gl_TexCoord[0].st + vec2(ds * -3.5, 0.0)) +
texture2D(originalTexture, gl_TexCoord[0].st + vec2(ds * -1.5, 0.0)) +
texture2D(originalTexture, gl_TexCoord[0].st + vec2(ds * 1.5, 0.0)) +
texture2D(originalTexture, gl_TexCoord[0].st + vec2(ds * 3.5, 0.0)) +
texture2D(originalTexture, gl_TexCoord[0].st + vec2(ds * 5.5, 0.0)) +
texture2D(originalTexture, gl_TexCoord[0].st + vec2(ds * 7.5, 0.0))) / 8.0;
}

View file

@ -0,0 +1,28 @@
#version 120
//
// vertical_blur.frag
// fragment shader
//
// Created by Andrzej Kapolka on 8/8/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
// the texture containing the original color
uniform sampler2D originalTexture;
// the texture containing the horizontally blurred color
uniform sampler2D horizontallyBlurredTexture;
void main(void) {
float dt = dFdy(gl_TexCoord[0].t);
vec4 blurred = (texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -7.5)) +
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -5.5)) +
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -3.5)) +
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -1.5)) +
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 1.5)) +
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 3.5)) +
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 5.5)) +
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 7.5))) / 8.0;
gl_FragColor = blurred * blurred.a + texture2D(originalTexture, gl_TexCoord[0].st) * (1.0 + blurred.a * 0.5);
}

View file

@ -3872,7 +3872,6 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng
_voxelFades.push_back(fade);
}
// store jurisdiction details for later use
// This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it
// but VoxelSceneStats thinks it's just returning a reference to it's contents. So we need to make a copy of the
// details from the VoxelSceneStats to construct the JurisdictionMap

View file

@ -46,6 +46,7 @@
#include "avatar/Avatar.h"
#include "avatar/HandControl.h"
#include "renderer/GeometryCache.h"
#include "renderer/GlowEffect.h"
#include "renderer/TextureCache.h"
#include "ui/BandwidthDialog.h"
#include "ui/ChatEntry.h"
@ -104,6 +105,7 @@ public:
void updateParticleSystem(float deltaTime);
QGLWidget* getGLWidget() { return _glWidget; }
Avatar* getAvatar() { return &_myAvatar; }
Audio* getAudio() { return &_audio; }
Camera* getCamera() { return &_myCamera; }
@ -122,6 +124,7 @@ public:
QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; }
GeometryCache* getGeometryCache() { return &_geometryCache; }
TextureCache* getTextureCache() { return &_textureCache; }
GlowEffect* getGlowEffect() { return &_glowEffect; }
void resetSongMixMenuItem();
void setupWorldLight(Camera& whichCamera);
@ -440,6 +443,7 @@ private:
TextureCache _textureCache;
ParticleSystem _particleSystem;
GlowEffect _glowEffect;
#ifndef _WIN32
Audio _audio;
@ -453,7 +457,6 @@ private:
VoxelPacketReceiver _voxelReceiver;
VoxelEditPacketSender _voxelEditSender;
unsigned char _incomingPacket[MAX_PACKET_SIZE];
int _packetCount;
int _packetsPerSecond;

View file

@ -14,9 +14,7 @@
#include "VoxelEditPacketSender.h"
VoxelEditPacketSender::VoxelEditPacketSender(Application* app) :
_app(app),
_currentType(PACKET_TYPE_UNKNOWN),
_currentSize(0)
_app(app)
{
}
@ -32,7 +30,7 @@ void VoxelEditPacketSender::sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail&
int totalBytesSent = 0;
if (createVoxelEditMessage(type, 0, 1, &detail, bufferOut, sizeOut)){
actuallySendMessage(bufferOut, sizeOut);
actuallySendMessage(UNKNOWN_NODE_ID, bufferOut, sizeOut); // sends to all servers... not ideal!
delete[] bufferOut;
}
@ -40,16 +38,13 @@ void VoxelEditPacketSender::sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail&
_app->_bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(totalBytesSent);
}
void VoxelEditPacketSender::actuallySendMessage(unsigned char* bufferOut, ssize_t sizeOut) {
qDebug("VoxelEditPacketSender::actuallySendMessage() sizeOut=%lu\n", sizeOut);
void VoxelEditPacketSender::actuallySendMessage(uint16_t nodeID, unsigned char* bufferOut, ssize_t sizeOut) {
qDebug("VoxelEditPacketSender::actuallySendMessage() sizeOut=%lu target NodeID=%d\n", sizeOut, nodeID);
NodeList* nodeList = NodeList::getInstance();
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
// We want to filter out edit messages for voxel servers based on the server's Jurisdiction
// But we can't really do that with a packed message, since each edit message could be destined
// for a different voxel server...
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER &&
((node->getNodeID() == nodeID) || (nodeID == (uint16_t)UNKNOWN_NODE_ID)) ) {
sockaddr* nodeAddress = node->getActiveSocket();
queuePacket(*nodeAddress, bufferOut, sizeOut);
}
@ -57,59 +52,64 @@ void VoxelEditPacketSender::actuallySendMessage(unsigned char* bufferOut, ssize_
}
void VoxelEditPacketSender::queueVoxelEditMessage(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length) {
/****
// We want to filter out edit messages for voxel servers based on the server's Jurisdiction
// But we can't really do that with a packed message, since each edit message could be destined
// for a different voxel server... So we need to actually manage multiple queued packets... one
// for each voxel server
NodeList* nodeList = NodeList::getInstance();
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
// we need to get the jurisdiction for this
// here we need to get the "pending packet" for this server
uint16_t nodeID = node->getNodeID();
const JurisdictionMap& map = _app->_voxelServerJurisdictions[nodeID];
if (map.isMyJurisdiction(codeColorBuffer, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN) {
// If we're switching type, then we send the last one and start over
if ((type != _currentType && _currentSize > 0) || (_currentSize + length >= MAX_PACKET_SIZE)) {
flushQueue();
initializePacket(type);
// do I need this???
//if (_pendingEditPackets.find(nodeID) == _pendingEditPackets.end()) {
// _pendingEditPackets[nodeID] =
//}
EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeID];
packetBuffer._nodeID = nodeID;
// If we're switching type, then we send the last one and start over
if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) ||
(packetBuffer._currentSize + length >= MAX_PACKET_SIZE)) {
flushQueue(packetBuffer);
initializePacket(packetBuffer, type);
}
// If the buffer is empty and not correctly initialized for our type...
if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) {
initializePacket(packetBuffer, type);
}
memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], codeColorBuffer, length);
packetBuffer._currentSize += length;
}
// If the buffer is empty and not correctly initialized for our type...
if (type != _currentType && _currentSize == 0) {
initializePacket(type);
}
memcpy(&_currentBuffer[_currentSize], codeColorBuffer, length);
_currentSize += length;
}
}
****/
// If we're switching type, then we send the last one and start over
if ((type != _currentType && _currentSize > 0) || (_currentSize + length >= MAX_PACKET_SIZE)) {
flushQueue();
initializePacket(type);
}
// If the buffer is empty and not correctly initialized for our type...
if (type != _currentType && _currentSize == 0) {
initializePacket(type);
}
memcpy(&_currentBuffer[_currentSize], codeColorBuffer, length);
_currentSize += length;
}
void VoxelEditPacketSender::flushQueue() {
actuallySendMessage(&_currentBuffer[0], _currentSize);
_currentSize = 0;
_currentType = PACKET_TYPE_UNKNOWN;
for (std::map<uint16_t,EditPacketBuffer>::iterator i = _pendingEditPackets.begin(); i != _pendingEditPackets.end(); i++) {
flushQueue(i->second);
}
}
void VoxelEditPacketSender::initializePacket(PACKET_TYPE type) {
_currentSize = populateTypeAndVersion(&_currentBuffer[0], type);
unsigned short int* sequenceAt = (unsigned short int*)&_currentBuffer[_currentSize];
*sequenceAt = 0;
_currentSize += sizeof(unsigned short int); // set to command + sequence
_currentType = type;
void VoxelEditPacketSender::flushQueue(EditPacketBuffer& packetBuffer) {
actuallySendMessage(packetBuffer._nodeID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize);
packetBuffer._currentSize = 0;
packetBuffer._currentType = PACKET_TYPE_UNKNOWN;
}
void VoxelEditPacketSender::initializePacket(EditPacketBuffer& packetBuffer, PACKET_TYPE type) {
packetBuffer._currentSize = populateTypeAndVersion(&packetBuffer._currentBuffer[0], type);
unsigned short int* sequenceAt = (unsigned short int*)&packetBuffer._currentBuffer[packetBuffer._currentSize];
*sequenceAt = 0;
packetBuffer._currentSize += sizeof(unsigned short int); // set to command + sequence
packetBuffer._currentType = type;
}

View file

@ -16,6 +16,15 @@
class Application;
class EditPacketBuffer {
public:
EditPacketBuffer() { _currentSize = 0; _currentType = PACKET_TYPE_UNKNOWN; _nodeID = UNKNOWN_NODE_ID; }
uint16_t _nodeID;
PACKET_TYPE _currentType;
unsigned char _currentBuffer[MAX_PACKET_SIZE];
ssize_t _currentSize;
};
class VoxelEditPacketSender : public PacketSender {
public:
VoxelEditPacketSender(Application* app);
@ -23,15 +32,14 @@ public:
// Some ways you can send voxel edit messages...
void sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail& detail); // sends it right away
void queueVoxelEditMessage(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length); // queues it into a multi-command packet
void flushQueue(); // flushes any queued packets
void flushQueue(); // flushes all queued packets
private:
void actuallySendMessage(unsigned char* bufferOut, ssize_t sizeOut);
void initializePacket(PACKET_TYPE type);
void actuallySendMessage(uint16_t nodeID, unsigned char* bufferOut, ssize_t sizeOut);
void initializePacket(EditPacketBuffer& packetBuffer, PACKET_TYPE type);
void flushQueue(EditPacketBuffer& packetBuffer); // flushes specific queued packet
Application* _app;
PACKET_TYPE _currentType ;
unsigned char _currentBuffer[MAX_PACKET_SIZE];
ssize_t _currentSize;
Application* _app;
std::map<uint16_t,EditPacketBuffer> _pendingEditPackets;
};
#endif // __shared__VoxelEditPacketSender__

View file

@ -10,14 +10,15 @@
#include <VoxelConstants.h>
#include "Application.h"
#include "VoxelFade.h"
const float VoxelFade::FADE_OUT_START = 0.5f;
const float VoxelFade::FADE_OUT_END = 0.0f;
const float VoxelFade::FADE_OUT_STEP = -0.005f;
const float VoxelFade::FADE_IN_START = 0.0f;
const float VoxelFade::FADE_OUT_END = 0.05f;
const float VoxelFade::FADE_OUT_STEP = 0.9f;
const float VoxelFade::FADE_IN_START = 0.05f;
const float VoxelFade::FADE_IN_END = 0.5f;
const float VoxelFade::FADE_IN_STEP = 0.005f;
const float VoxelFade::FADE_IN_STEP = 1.1f;
const float VoxelFade::DEFAULT_RED = 0.5f;
const float VoxelFade::DEFAULT_GREEN = 0.5f;
const float VoxelFade::DEFAULT_BLUE = 0.5f;
@ -32,6 +33,8 @@ VoxelFade::VoxelFade(FadeDirection direction, float red, float green, float blue
}
void VoxelFade::render() {
Application::getInstance()->getGlowEffect()->begin();
glDisable(GL_LIGHTING);
glPushMatrix();
glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE);
@ -45,7 +48,10 @@ void VoxelFade::render() {
glPopMatrix();
glEnable(GL_LIGHTING);
opacity += (direction == FADE_OUT) ? FADE_OUT_STEP : FADE_IN_STEP;
Application::getInstance()->getGlowEffect()->end();
opacity *= (direction == FADE_OUT) ? FADE_OUT_STEP : FADE_IN_STEP;
}
bool VoxelFade::isDone() const {
@ -55,4 +61,4 @@ bool VoxelFade::isDone() const {
return opacity >= FADE_IN_END;
}
return true; // unexpected case, assume we're done
}
}

View file

@ -695,8 +695,7 @@ void VoxelSystem::render(bool texture) {
applyScaleAndBindProgram(texture);
// for performance, disable blending and enable backface culling
glDisable(GL_BLEND);
// for performance, enable backface culling
glEnable(GL_CULL_FACE);
// draw the number of voxels we have
@ -704,7 +703,6 @@ void VoxelSystem::render(bool texture) {
glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
glEnable(GL_BLEND);
glDisable(GL_CULL_FACE);
removeScaleAndReleaseProgram(texture);

View file

@ -0,0 +1,128 @@
//
// GlowEffect.cpp
// interface
//
// Created by Andrzej Kapolka on 8/7/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
// include this before QGLWidget, which includes an earlier version of OpenGL
#include "InterfaceConfig.h"
#include <QOpenGLFramebufferObject>
#include "Application.h"
#include "GlowEffect.h"
#include "ProgramObject.h"
static ProgramObject* createBlurProgram(const QString& direction) {
ProgramObject* program = new ProgramObject();
program->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/" + direction + "_blur.frag");
program->link();
program->bind();
program->setUniformValue("originalTexture", 0);
program->release();
return program;
}
void GlowEffect::init() {
switchToResourcesParentIfRequired();
_horizontalBlurProgram = createBlurProgram("horizontal");
_verticalBlurProgram = createBlurProgram("vertical");
_verticalBlurProgram->bind();
_verticalBlurProgram->setUniformValue("horizontallyBlurredTexture", 1);
_verticalBlurProgram->release();
}
void GlowEffect::prepare() {
Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_isEmpty = true;
}
void GlowEffect::begin(float amount) {
glBlendColor(0.0f, 0.0f, 0.0f, amount);
_isEmpty = false;
}
void GlowEffect::end() {
glBlendColor(0.0f, 0.0f, 0.0f, 0.0f);
}
static void renderFullscreenQuad() {
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
glEnd();
}
void GlowEffect::render() {
QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject();
primaryFBO->release();
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
if (_isEmpty) {
// copy the primary to the screen
if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
QOpenGLFramebufferObject::blitFramebuffer(NULL, primaryFBO);
} else {
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glColor3f(1.0f, 1.0f, 1.0f);
renderFullscreenQuad();
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
}
} else {
// render the primary to the secondary with the horizontal blur
QOpenGLFramebufferObject* secondaryFBO =
Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject();
secondaryFBO->bind();
_horizontalBlurProgram->bind();
renderFullscreenQuad();
_horizontalBlurProgram->release();
secondaryFBO->release();
// render the secondary to the screen with the vertical blur
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture());
_verticalBlurProgram->bind();
renderFullscreenQuad();
_verticalBlurProgram->release();
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
}
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, 0);
}

View file

@ -0,0 +1,34 @@
//
// GlowEffect.h
// interface
//
// Created by Andrzej Kapolka on 8/7/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__GlowEffect__
#define __interface__GlowEffect__
class ProgramObject;
class GlowEffect {
public:
void init();
void prepare();
void begin(float amount = 1.0f);
void end();
void render();
private:
ProgramObject* _horizontalBlurProgram;
ProgramObject* _verticalBlurProgram;
bool _isEmpty;
};
#endif /* defined(__interface__GlowEffect__) */

View file

@ -5,17 +5,28 @@
// Created by Andrzej Kapolka on 8/6/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <QGLWidget>
#include <QOpenGLFramebufferObject>
#include <glm/gtc/random.hpp>
#include "Application.h"
#include "TextureCache.h"
TextureCache::TextureCache() : _permutationNormalTextureID(0) {
TextureCache::TextureCache() : _permutationNormalTextureID(0),
_primaryFramebufferObject(NULL), _secondaryFramebufferObject(NULL) {
}
TextureCache::~TextureCache() {
if (_permutationNormalTextureID != 0) {
glDeleteTextures(1, &_permutationNormalTextureID);
}
if (_primaryFramebufferObject != NULL) {
delete _primaryFramebufferObject;
}
if (_secondaryFramebufferObject != NULL) {
delete _secondaryFramebufferObject;
}
}
GLuint TextureCache::getPermutationNormalTextureID() {
@ -43,3 +54,35 @@ GLuint TextureCache::getPermutationNormalTextureID() {
}
return _permutationNormalTextureID;
}
QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() {
if (_primaryFramebufferObject == NULL) {
_primaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size(),
QOpenGLFramebufferObject::Depth);
Application::getInstance()->getGLWidget()->installEventFilter(this);
}
return _primaryFramebufferObject;
}
QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() {
if (_secondaryFramebufferObject == NULL) {
_secondaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size());
Application::getInstance()->getGLWidget()->installEventFilter(this);
}
return _secondaryFramebufferObject;
}
bool TextureCache::eventFilter(QObject* watched, QEvent* event) {
if (event->type() == QEvent::Resize) {
QSize size = static_cast<QResizeEvent*>(event)->size();
if (_primaryFramebufferObject != NULL && _primaryFramebufferObject->size() != size) {
delete _primaryFramebufferObject;
_primaryFramebufferObject = NULL;
}
if (_secondaryFramebufferObject != NULL && _secondaryFramebufferObject->size() != size) {
delete _secondaryFramebufferObject;
_secondaryFramebufferObject = NULL;
}
}
return false;
}

View file

@ -9,9 +9,13 @@
#ifndef __interface__TextureCache__
#define __interface__TextureCache__
#include <QObject>
#include "InterfaceConfig.h"
class TextureCache {
class QOpenGLFramebufferObject;
class TextureCache : public QObject {
public:
TextureCache();
@ -19,9 +23,17 @@ public:
GLuint getPermutationNormalTextureID();
QOpenGLFramebufferObject* getPrimaryFramebufferObject();
QOpenGLFramebufferObject* getSecondaryFramebufferObject();
virtual bool eventFilter(QObject* watched, QEvent* event);
private:
GLuint _permutationNormalTextureID;
QOpenGLFramebufferObject* _primaryFramebufferObject;
QOpenGLFramebufferObject* _secondaryFramebufferObject;
};
#endif /* defined(__interface__TextureCache__) */