Merge branch 'master' of https://github.com/highfidelity/hifi into gpuStreamizing

Conflicts:
	libraries/gpu/src/gpu/GLBackend.cpp
This commit is contained in:
ZappoMan 2015-01-28 10:46:30 -08:00
commit 6821f31f14
37 changed files with 1414 additions and 352 deletions

View file

@ -7,6 +7,7 @@
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
* [Bullet Physics Engine](https://code.google.com/p/bullet/downloads/list) ~> 2.82
* [Gverb](https://github.com/highfidelity/gverb/archive/master.zip) (direct download to latest version)
### OS Specific Build Guides
* [BUILD_WIN.md](BUILD_WIN.md) - additional instructions for Windows.
@ -54,11 +55,11 @@ In the examples below the variable $NAME would be replaced by the name of the de
####QXmpp
You can find QXmpp [here](https://github.com/qxmpp-project/qxmpp). The inclusion of the QXmpp enables text chat in the Interface client.
You can [find QXmpp here](https://github.com/qxmpp-project/qxmpp), 0.7.6 is the version you want. The inclusion of the QXmpp enables text chat in the Interface client.
OS X users who tap our [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) can install QXmpp via homebrew - `brew install highfidelity/formulas/qxmpp`.
####Devices
You can support external input/output devices such as Leap Motion, Faceshift, PrioVR, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
You can support external input/output devices such as Oculus Rift, Leap Motion, Faceshift, PrioVR, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.

View file

@ -38,6 +38,8 @@ Once Qt is installed, you need to manually configure the following:
###External Libraries
As it stands, Hifi/Interface is a 32-bit application, so all libraries should also be 32-bit.
CMake will need to know where the headers and libraries for required external dependencies are.
The recommended route for CMake to find the external dependencies is to place all of the dependencies in one folder and set one ENV variable - HIFI_LIB_DIR. That ENV variable should point to a directory with the following structure:
@ -75,7 +77,7 @@ As with the Qt libraries, you will need to make sure that directories containing
###OpenSSL
QT will use OpenSSL if it's available, but it doesn't install it, so you must install it separately.
Qt will use OpenSSL if it's available, but it doesn't install it, so you must install it separately.
Your system may already have several versions of the OpenSSL DLL's (ssleay32.dll, libeay32.dll) lying around, but they may be the wrong version. If these DLL's are in the PATH then QT will try to use them, and if they're the wrong version then you will see the following errors in the console:
@ -89,7 +91,7 @@ Your system may already have several versions of the OpenSSL DLL's (ssleay32.dll
To prevent these problems, install OpenSSL yourself. Download the following binary packages [from this website](http://slproweb.com/products/Win32OpenSSL.html):
* Visual C++ 2008 Redistributables
* Win32 OpenSSL v1.0.1h
* Win32 OpenSSL v1.0.1L
Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
@ -133,6 +135,20 @@ This package contains only headers, so there's nothing to add to the PATH.
Be careful with glm. For the folder other libraries would normally call 'include', the folder containing the headers, glm opts to use 'glm'. You will have a glm folder nested inside the top-level glm folder.
###Gverb
1. Go to https://github.com/highfidelity/gverb
Or download the sources directly via this link:
https://github.com/highfidelity/gverb/archive/master.zip
2. Extract the archive
3. Place the directories “include” and “src” in interface/external/gverb
(Normally next to this readme)
4. Clear your build directory, run cmake, build and you should be all set.
###Bullet
Bullet 2.82 source can be [downloaded here](https://code.google.com/p/bullet/downloads/detail?name=bullet-2.82-r2704.zip). Bullet does not come with prebuilt libraries, you need to make those yourself.

View file

@ -13,6 +13,7 @@
#include <QtCore/QEventLoop>
#include <QtCore/QStandardPaths>
#include <QtCore/QTimer>
#include <QtNetwork/QNetworkDiskCache>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
@ -170,6 +171,11 @@ void Agent::run() {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL));
QNetworkDiskCache* cache = new QNetworkDiskCache();
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "agentCache");
networkAccessManager.setCache(cache);
qDebug() << "Downloading script at" << scriptURL.toString();
QEventLoop loop;

View file

@ -98,8 +98,16 @@ function setupAudioMenus() {
}
}
function onDevicechanged() {
Menu.removeMenu("Tools > Audio");
setupAudioMenus();
}
// Have a small delay before the menu's get setup and the audio devices can switch to the last selected ones
Script.setTimeout(function() { setupAudioMenus(); }, 5000);
Script.setTimeout(function () {
AudioDevice.deviceChanged.connect(onDevicechanged);
setupAudioMenus();
}, 5000);
function scriptEnding() {
Menu.removeMenu("Tools > Audio");

View file

@ -33,6 +33,7 @@
#include <QMenuBar>
#include <QMouseEvent>
#include <QNetworkReply>
#include <QNetworkDiskCache>
#include <QOpenGLFramebufferObject>
#include <QObject>
#include <QWheelEvent>
@ -135,6 +136,9 @@ static unsigned STARFIELD_SEED = 1;
static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored
const qint64 MAXIMUM_CACHE_SIZE = 10737418240; // 10GB
static QTimer* idleTimer = NULL;
const QString CHECK_VERSION_URL = "https://highfidelity.io/latestVersion.xml";
@ -383,7 +387,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
connect(billboardPacketTimer, &QTimer::timeout, _myAvatar, &MyAvatar::sendBillboardPacket);
billboardPacketTimer->start(AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS);
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkDiskCache* cache = new QNetworkDiskCache();
cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE);
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache");
networkAccessManager.setCache(cache);
ResourceCache::setRequestLimit(3);

View file

@ -106,6 +106,15 @@ Audio::Audio() :
// Initialize GVerb
initGverb();
const qint64 DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
_inputDevices = getDeviceNames(QAudio::AudioInput);
_outputDevices = getDeviceNames(QAudio::AudioOutput);
QTimer* updateTimer = new QTimer(this);
connect(updateTimer, &QTimer::timeout, this, &Audio::checkDevices);
updateTimer->start(DEVICE_CHECK_INTERVAL_MSECS);
}
void Audio::reset() {
@ -1116,6 +1125,18 @@ qint64 Audio::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
return bytesWritten;
}
void Audio::checkDevices() {
QVector<QString> inputDevices = getDeviceNames(QAudio::AudioInput);
QVector<QString> outputDevices = getDeviceNames(QAudio::AudioOutput);
if (inputDevices != _inputDevices || outputDevices != _outputDevices) {
_inputDevices = inputDevices;
_outputDevices = outputDevices;
emit deviceChanged();
}
}
void Audio::loadSettings() {
_receivedAudioStream.loadSettings();

View file

@ -178,6 +178,7 @@ public slots:
signals:
bool muteToggled();
void inputReceived(const QByteArray& inputSamples);
void deviceChanged();
protected:
Audio();
@ -276,6 +277,10 @@ private:
AudioIOStats _stats;
AudioNoiseGate _inputGate;
QVector<QString> _inputDevices;
QVector<QString> _outputDevices;
void checkDevices();
};

View file

@ -21,6 +21,8 @@ AudioDeviceScriptingInterface* AudioDeviceScriptingInterface::getInstance() {
AudioDeviceScriptingInterface::AudioDeviceScriptingInterface() {
connect(DependencyManager::get<Audio>().data(), &Audio::muteToggled,
this, &AudioDeviceScriptingInterface::muteToggled);
connect(DependencyManager::get<Audio>().data(), &Audio::deviceChanged,
this, &AudioDeviceScriptingInterface::deviceChanged);
}
bool AudioDeviceScriptingInterface::setInputDevice(const QString& deviceName) {

View file

@ -49,6 +49,7 @@ private:
signals:
void muteToggled();
void deviceChanged();
};
#endif // hifi_AudioDeviceScriptingInterface_h

View file

@ -14,6 +14,7 @@
#include <ByteCountCoding.h>
#include <GLMHelpers.h>
#include <Octree.h>
#include <PhysicsHelpers.h>
#include <RegisteredMetaTypes.h>
#include <SharedUtil.h> // usecTimestampNow()
@ -711,10 +712,22 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) {
} else {
// NOTE: angularSpeed is currently in degrees/sec!!!
// TODO: Andrew to convert to radians/sec
float angle = timeElapsed * glm::radians(angularSpeed);
glm::vec3 axis = _angularVelocity / angularSpeed;
glm::quat dQ = glm::angleAxis(angle, axis);
glm::quat rotation = glm::normalize(dQ * getRotation());
glm::vec3 angularVelocity = glm::radians(_angularVelocity);
// for improved agreement with the way Bullet integrates rotations we use an approximation
// and break the integration into bullet-sized substeps
glm::quat rotation = getRotation();
float dt = timeElapsed;
while (dt > PHYSICS_ENGINE_FIXED_SUBSTEP) {
glm::quat dQ = computeBulletRotationStep(angularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP);
rotation = glm::normalize(dQ * rotation);
dt -= PHYSICS_ENGINE_FIXED_SUBSTEP;
}
// NOTE: this final partial substep can drift away from a real Bullet simulation however
// it only becomes significant for rapidly rotating objects
// (e.g. around PI/4 radians per substep, or 7.5 rotations/sec at 60 substeps/sec).
glm::quat dQ = computeBulletRotationStep(angularVelocity, dt);
rotation = glm::normalize(dQ * rotation);
setRotation(rotation);
}
}

View file

@ -226,16 +226,16 @@ public:
glm::mat4 offset;
int leftEyeJointIndex;
int rightEyeJointIndex;
int neckJointIndex;
int rootJointIndex;
int leanJointIndex;
int headJointIndex;
int leftHandJointIndex;
int rightHandJointIndex;
int leftToeJointIndex;
int rightToeJointIndex;
int leftEyeJointIndex = -1;
int rightEyeJointIndex = -1;
int neckJointIndex = -1;
int rootJointIndex = -1;
int leanJointIndex = -1;
int headJointIndex = -1;
int leftHandJointIndex = -1;
int rightHandJointIndex = -1;
int leftToeJointIndex = -1;
int rightToeJointIndex = -1;
QVector<int> humanIKJointIndices;

View file

@ -23,6 +23,7 @@ Batch::Batch() :
_resources(),
_data(),
_buffers(),
_textures(),
_streamFormats(),
_transforms()
{
@ -38,6 +39,7 @@ void Batch::clear() {
_resources.clear();
_data.clear();
_buffers.clear();
_textures.clear();
_streamFormats.clear();
_transforms.clear();
}
@ -171,3 +173,14 @@ void Batch::setUniformBuffer(uint32 slot, const BufferView& view) {
}
void Batch::setUniformTexture(uint32 slot, const TexturePointer& texture) {
ADD_COMMAND(setUniformTexture);
_params.push_back(_textures.cache(texture));
_params.push_back(slot);
}
void Batch::setUniformTexture(uint32 slot, const TextureView& view) {
setUniformTexture(slot, view._texture);
}

View file

@ -19,6 +19,7 @@
#include <vector>
#include "Stream.h"
#include "Texture.h"
#if defined(NSIGHT_FOUND)
#include "nvToolsExt.h"
@ -94,6 +95,10 @@ public:
void setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size);
void setUniformBuffer(uint32 slot, const BufferView& view); // not a command, just a shortcut from a BufferView
void setUniformTexture(uint32 slot, const TexturePointer& view);
void setUniformTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView
// TODO: As long as we have gl calls explicitely issued from interface
// code, we need to be able to record and batch these calls. THe long
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
@ -150,10 +155,6 @@ public:
void _glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
void _glMaterialf(GLenum face, GLenum pname, GLfloat param);
void _glMaterialfv(GLenum face, GLenum pname, const GLfloat *params);
enum Command {
COMMAND_draw = 0,
COMMAND_drawIndexed,
@ -169,6 +170,7 @@ public:
COMMAND_setProjectionTransform,
COMMAND_setUniformBuffer,
COMMAND_setUniformTexture,
// TODO: As long as we have gl calls explicitely issued from interface
// code, we need to be able to record and batch these calls. THe long
@ -221,10 +223,7 @@ public:
COMMAND_glEnableVertexAttribArray,
COMMAND_glDisableVertexAttribArray,
COMMAND_glColor4f,
COMMAND_glMaterialf,
COMMAND_glMaterialfv,
COMMAND_glColor4f,
NUM_COMMANDS,
};
@ -294,6 +293,7 @@ public:
};
typedef Cache<BufferPointer>::Vector BufferCaches;
typedef Cache<TexturePointer>::Vector TextureCaches;
typedef Cache<Stream::FormatPointer>::Vector StreamFormatCaches;
typedef Cache<Transform>::Vector TransformCaches;
@ -332,6 +332,7 @@ public:
Bytes _data;
BufferCaches _buffers;
TextureCaches _textures;
StreamFormatCaches _streamFormats;
TransformCaches _transforms;

View file

@ -14,6 +14,7 @@
#include <assert.h>
#include "Resource.h"
#include "Texture.h"
namespace gpu {
@ -39,6 +40,17 @@ public:
void syncGPUObject(const Buffer& buffer);
template< typename T >
static void setGPUObject(const Texture& texture, T* to) {
texture.setGPUObject(reinterpret_cast<GPUObject*>(to));
}
template< typename T >
static T* getGPUObject(const Texture& texture) {
return reinterpret_cast<T*>(texture.getGPUObject());
}
void syncGPUObject(const Texture& texture);
protected:
};

View file

@ -93,19 +93,24 @@ static const int DIMENSION_COUNT[NUM_DIMENSIONS] = {
// Provide information on how to use the element
enum Semantic {
RAW = 0, // used as RAW memory
RGB,
RGBA,
BGRA,
XYZ,
XYZW,
POS_XYZ,
POS_XYZW,
QUAT,
DIR_XYZ,
UV,
R8,
INDEX, //used by index buffer of a mesh
PART, // used by part buffer of a mesh
DEPTH, // Depth buffer
DEPTH_STENCIL, // Depth Stencil buffer
SRGB,
SRGBA,
SBGRA,
NUM_SEMANTICS,
};
@ -124,7 +129,7 @@ public:
_dimension(SCALAR),
_type(INT8)
{}
Semantic getSemantic() const { return (Semantic)_semantic; }
Dimension getDimension() const { return (Dimension)_dimension; }
@ -135,13 +140,22 @@ public:
uint32 getSize() const { return DIMENSION_COUNT[_dimension] * TYPE_SIZE[_type]; }
protected:
uint16 getRaw() const { return *((uint16*) (this)); }
bool operator ==(const Element& right) const {
return getRaw() == right.getRaw();
}
bool operator !=(const Element& right) const {
return getRaw() != right.getRaw();
}
protected:
uint8 _semantic;
uint8 _dimension : 4;
uint8 _type : 4;
};
};

View file

@ -1,6 +1,6 @@
//
// GLBackend.cpp
// interface/src/gpu
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 10/27/2014.
// Copyright 2014 High Fidelity, Inc.
@ -8,13 +8,7 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include <QDebug>
#include "Batch.h"
using namespace gpu;
#include "GLBackendShared.h"
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
{
@ -32,6 +26,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
(&::gpu::GLBackend::do_setProjectionTransform),
(&::gpu::GLBackend::do_setUniformBuffer),
(&::gpu::GLBackend::do_setUniformTexture),
(&::gpu::GLBackend::do_glEnable),
(&::gpu::GLBackend::do_glDisable),
@ -82,42 +77,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
(&::gpu::GLBackend::do_glDisableVertexAttribArray),
(&::gpu::GLBackend::do_glColor4f),
(&::gpu::GLBackend::do_glMaterialf),
(&::gpu::GLBackend::do_glMaterialfv),
};
static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = {
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
GL_TRIANGLES,
GL_TRIANGLE_STRIP,
GL_TRIANGLE_FAN,
GL_QUADS,
GL_QUAD_STRIP,
};
static const GLenum _elementTypeToGLType[NUM_TYPES]= {
GL_FLOAT,
GL_INT,
GL_UNSIGNED_INT,
GL_HALF_FLOAT,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_BYTE,
GL_UNSIGNED_BYTE,
GL_FLOAT,
GL_INT,
GL_UNSIGNED_INT,
GL_HALF_FLOAT,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_BYTE,
GL_UNSIGNED_BYTE
};
GLBackend::GLBackend() :
_input(),
_transform()
@ -176,9 +137,6 @@ void GLBackend::checkGLError() {
}
}
//#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError()
#define CHECK_GL_ERROR()
void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
updateInput();
updateTransform();
@ -510,6 +468,18 @@ void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) {
CHECK_GL_ERROR();
}
void GLBackend::do_setUniformTexture(Batch& batch, uint32 paramOffset) {
GLuint slot = batch._params[paramOffset + 1]._uint;
TexturePointer uniformTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
GLuint to = getTextureID(uniformTexture);
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, to);
CHECK_GL_ERROR();
}
// TODO: As long as we have gl calls explicitely issued from interface
// code, we need to be able to record and batch these calls. THe long
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
@ -1079,40 +1049,6 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) {
CHECK_GL_ERROR();
}
void Batch::_glMaterialf(GLenum face, GLenum pname, GLfloat param) {
ADD_COMMAND_GL(glMaterialf);
_params.push_back(param);
_params.push_back(pname);
_params.push_back(face);
DO_IT_NOW(_glMaterialf, 3);
}
void GLBackend::do_glMaterialf(Batch& batch, uint32 paramOffset) {
glMaterialf(
batch._params[paramOffset + 2]._uint,
batch._params[paramOffset + 1]._uint,
batch._params[paramOffset + 0]._float);
CHECK_GL_ERROR();
}
void Batch::_glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) {
ADD_COMMAND_GL(glMaterialfv);
_params.push_back(cacheData(4 * sizeof(float), params));
_params.push_back(pname);
_params.push_back(face);
DO_IT_NOW(_glMaterialfv, 3);
}
void GLBackend::do_glMaterialfv(Batch& batch, uint32 paramOffset) {
glMaterialfv(
batch._params[paramOffset + 2]._uint,
batch._params[paramOffset + 1]._uint,
(const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint));
CHECK_GL_ERROR();
}
GLBackend::GLBuffer::GLBuffer() :
_stamp(0),
_buffer(0),
@ -1158,3 +1094,4 @@ GLuint GLBackend::getBufferID(const Buffer& buffer) {
GLBackend::syncGPUObject(buffer);
return Backend::getGPUObject<GLBackend::GLBuffer>(buffer)->_buffer;
}

View file

@ -1,6 +1,6 @@
//
// GLBackend.h
// interface/src/gpu
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 10/27/2014.
// Copyright 2014 High Fidelity, Inc.
@ -34,7 +34,7 @@ public:
class GLBuffer {
public:
Stamp _stamp;
Stamp _stamp;
GLuint _buffer;
GLuint _size;
@ -42,9 +42,21 @@ public:
~GLBuffer();
};
static void syncGPUObject(const Buffer& buffer);
static GLuint getBufferID(const Buffer& buffer);
class GLTexture {
public:
Stamp _storageStamp;
Stamp _contentStamp;
GLuint _texture;
GLuint _size;
GLTexture();
~GLTexture();
};
static void syncGPUObject(const Texture& texture);
static GLuint getTextureID(const TexturePointer& texture);
static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
static const int MAX_NUM_INPUT_BUFFERS = 16;
@ -124,6 +136,7 @@ protected:
// Shader Stage
void do_setUniformBuffer(Batch& batch, uint32 paramOffset);
void do_setUniformTexture(Batch& batch, uint32 paramOffset);
void updateShader();
struct ShaderStageState {
@ -188,9 +201,6 @@ protected:
void do_glColor4f(Batch& batch, uint32 paramOffset);
void do_glMaterialf(Batch& batch, uint32 paramOffset);
void do_glMaterialfv(Batch& batch, uint32 paramOffset);
typedef void (GLBackend::*CommandCall)(Batch&, uint32);
static CommandCall _commandCalls[Batch::NUM_COMMANDS];

View file

@ -0,0 +1,55 @@
//
// GLBackendShared.h
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 1/22/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_GLBackend_Shared_h
#define hifi_gpu_GLBackend_Shared_h
#include "GLBackend.h"
#include <QDebug>
#include "Batch.h"
using namespace gpu;
static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = {
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
GL_TRIANGLES,
GL_TRIANGLE_STRIP,
GL_TRIANGLE_FAN,
GL_QUADS,
GL_QUAD_STRIP,
};
static const GLenum _elementTypeToGLType[NUM_TYPES]= {
GL_FLOAT,
GL_INT,
GL_UNSIGNED_INT,
GL_HALF_FLOAT,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_BYTE,
GL_UNSIGNED_BYTE,
GL_FLOAT,
GL_INT,
GL_UNSIGNED_INT,
GL_HALF_FLOAT,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_BYTE,
GL_UNSIGNED_BYTE
};
#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError()
//#define CHECK_GL_ERROR()
#endif

View file

@ -0,0 +1,331 @@
//
// GLBackendTexture.cpp
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 1/19/2015.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackendShared.h"
GLBackend::GLTexture::GLTexture() :
_storageStamp(0),
_contentStamp(0),
_texture(0),
_size(0)
{}
GLBackend::GLTexture::~GLTexture() {
if (_texture != 0) {
glDeleteTextures(1, &_texture);
}
}
class GLTexelFormat {
public:
GLenum internalFormat;
GLenum format;
GLenum type;
static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) {
if (dstFormat != srcFormat) {
GLTexelFormat texel = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE};
switch(dstFormat.getDimension()) {
case gpu::SCALAR: {
texel.format = GL_RED;
texel.type = _elementTypeToGLType[dstFormat.getType()];
switch(dstFormat.getSemantic()) {
case gpu::RGB:
case gpu::RGBA:
texel.internalFormat = GL_RED;
break;
case gpu::DEPTH:
texel.internalFormat = GL_DEPTH_COMPONENT;
break;
default:
qDebug() << "Unknown combination of texel format";
}
break;
}
case gpu::VEC2: {
texel.format = GL_RG;
texel.type = _elementTypeToGLType[dstFormat.getType()];
switch(dstFormat.getSemantic()) {
case gpu::RGB:
case gpu::RGBA:
texel.internalFormat = GL_RG;
break;
case gpu::DEPTH_STENCIL:
texel.internalFormat = GL_DEPTH_STENCIL;
break;
default:
qDebug() << "Unknown combination of texel format";
}
break;
}
case gpu::VEC3: {
texel.format = GL_RGB;
texel.type = _elementTypeToGLType[dstFormat.getType()];
switch(dstFormat.getSemantic()) {
case gpu::RGB:
case gpu::RGBA:
texel.internalFormat = GL_RGB;
break;
default:
qDebug() << "Unknown combination of texel format";
}
break;
}
case gpu::VEC4: {
texel.format = GL_RGBA;
texel.type = _elementTypeToGLType[dstFormat.getType()];
switch(srcFormat.getSemantic()) {
case gpu::BGRA:
case gpu::SBGRA:
texel.format = GL_BGRA;
break;
case gpu::RGB:
case gpu::RGBA:
case gpu::SRGB:
case gpu::SRGBA:
default:
break;
};
switch(dstFormat.getSemantic()) {
case gpu::RGB:
texel.internalFormat = GL_RGB;
break;
case gpu::RGBA:
texel.internalFormat = GL_RGBA;
break;
case gpu::SRGB:
texel.internalFormat = GL_SRGB;
break;
case gpu::SRGBA:
texel.internalFormat = GL_SRGB_ALPHA;
break;
default:
qDebug() << "Unknown combination of texel format";
}
break;
}
default:
qDebug() << "Unknown combination of texel format";
}
return texel;
} else {
GLTexelFormat texel = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE};
switch(dstFormat.getDimension()) {
case gpu::SCALAR: {
texel.format = GL_RED;
texel.type = _elementTypeToGLType[dstFormat.getType()];
switch(dstFormat.getSemantic()) {
case gpu::RGB:
case gpu::RGBA:
texel.internalFormat = GL_RED;
break;
case gpu::DEPTH:
texel.internalFormat = GL_DEPTH_COMPONENT;
break;
default:
qDebug() << "Unknown combination of texel format";
}
break;
}
case gpu::VEC2: {
texel.format = GL_RG;
texel.type = _elementTypeToGLType[dstFormat.getType()];
switch(dstFormat.getSemantic()) {
case gpu::RGB:
case gpu::RGBA:
texel.internalFormat = GL_RG;
break;
case gpu::DEPTH_STENCIL:
texel.internalFormat = GL_DEPTH_STENCIL;
break;
default:
qDebug() << "Unknown combination of texel format";
}
break;
}
case gpu::VEC3: {
texel.format = GL_RGB;
texel.type = _elementTypeToGLType[dstFormat.getType()];
switch(dstFormat.getSemantic()) {
case gpu::RGB:
case gpu::RGBA:
texel.internalFormat = GL_RGB;
break;
case gpu::SRGB:
case gpu::SRGBA:
texel.internalFormat = GL_SRGB; // standard 2.2 gamma correction color
break;
default:
qDebug() << "Unknown combination of texel format";
}
break;
}
case gpu::VEC4: {
texel.format = GL_RGBA;
texel.type = _elementTypeToGLType[dstFormat.getType()];
switch(dstFormat.getSemantic()) {
case gpu::RGB:
texel.internalFormat = GL_RGB;
break;
case gpu::RGBA:
texel.internalFormat = GL_RGBA;
break;
case gpu::SRGB:
texel.internalFormat = GL_SRGB;
break;
case gpu::SRGBA:
texel.internalFormat = GL_SRGB_ALPHA; // standard 2.2 gamma correction color
break;
default:
qDebug() << "Unknown combination of texel format";
}
break;
}
default:
qDebug() << "Unknown combination of texel format";
}
return texel;
}
}
};
void GLBackend::syncGPUObject(const Texture& texture) {
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(texture);
// If GPU object already created and in sync
bool needUpdate = false;
if (object && (object->_storageStamp == texture.getStamp())) {
// If gpu object info is in sync with sysmem version
if (object->_contentStamp >= texture.getDataStamp()) {
// Then all good, GPU object is ready to be used
return;
} else {
// Need to update the content of the GPU object from the source sysmem of the texture
needUpdate = true;
}
} else if (!texture.isDefined()) {
// NO texture definition yet so let's avoid thinking
return;
}
// need to have a gpu object?
if (!object) {
object = new GLTexture();
glGenTextures(1, &object->_texture);
CHECK_GL_ERROR();
Backend::setGPUObject(texture, object);
}
// GO through the process of allocating the correct storage and/or update the content
switch (texture.getType()) {
case Texture::TEX_2D: {
if (needUpdate) {
if (texture.isStoredMipAvailable(0)) {
GLint boundTex = -1;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
Texture::PixelsPointer mip = texture.accessStoredMip(0);
const GLvoid* bytes = mip->_sysmem.read<Resource::Byte>();
Element srcFormat = mip->_format;
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
glBindTexture(GL_TEXTURE_2D, object->_texture);
glTexSubImage2D(GL_TEXTURE_2D, 0,
texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0,
texelFormat.format, texelFormat.type, bytes);
if (texture.isAutogenerateMips()) {
glGenerateMipmap(GL_TEXTURE_2D);
}
glBindTexture(GL_TEXTURE_2D, boundTex);
object->_contentStamp = texture.getDataStamp();
}
} else {
const GLvoid* bytes = 0;
Element srcFormat = texture.getTexelFormat();
if (texture.isStoredMipAvailable(0)) {
Texture::PixelsPointer mip = texture.accessStoredMip(0);
bytes = mip->_sysmem.read<Resource::Byte>();
srcFormat = mip->_format;
object->_contentStamp = texture.getDataStamp();
}
GLint boundTex = -1;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
glBindTexture(GL_TEXTURE_2D, object->_texture);
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
glTexImage2D(GL_TEXTURE_2D, 0,
texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0,
texelFormat.format, texelFormat.type, bytes);
if (bytes && texture.isAutogenerateMips()) {
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
glBindTexture(GL_TEXTURE_2D, boundTex);
object->_storageStamp = texture.getStamp();
object->_size = texture.getSize();
}
break;
}
default:
qDebug() << "GLBackend::syncGPUObject(const Texture&) case for Texture Type " << texture.getType() << " not supported";
}
CHECK_GL_ERROR();
}
GLuint GLBackend::getTextureID(const TexturePointer& texture) {
if (!texture) {
return 0;
}
GLBackend::syncGPUObject(*texture);
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texture);
if (object) {
return object->_texture;
} else {
return 0;
}
}

View file

@ -1,6 +1,6 @@
//
// Resource.cpp
// interface/src/gpu
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 10/8/2014.
// Copyright 2014 High Fidelity, Inc.

View file

@ -1,6 +1,6 @@
//
// Resource.h
// interface/src/gpu
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 10/8/2014.
// Copyright 2014 High Fidelity, Inc.
@ -79,18 +79,20 @@ protected:
// Access the byte array.
// The edit version allow to map data.
inline const Byte* readData() const { return _data; }
inline Byte* editData() { _stamp++; return _data; }
const Byte* readData() const { return _data; }
Byte* editData() { _stamp++; return _data; }
template< typename T > const T* read() const { return reinterpret_cast< T* > ( _data ); }
template< typename T > T* edit() { _stamp++; return reinterpret_cast< T* > ( _data ); }
// Access the current version of the sysmem, used to compare if copies are in sync
inline Stamp getStamp() const { return _stamp; }
Stamp getStamp() const { return _stamp; }
static Size allocateMemory(Byte** memAllocated, Size size);
static void deallocateMemory(Byte* memDeallocated, Size size);
bool isAvailable() const { return (_data != 0); }
private:
Stamp _stamp;
Size _size;
@ -136,9 +138,9 @@ public:
protected:
Sysmem* _sysmem;
Sysmem* _sysmem = NULL;
mutable GPUObject* _gpuObject;
mutable GPUObject* _gpuObject = NULL;
// This shouldn't be used by anything else than the Backend class with the proper casting.
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
@ -371,64 +373,6 @@ public:
}
};
// TODO: For now TextureView works with Buffer as a place holder for the Texture.
// The overall logic should be about the same except that the Texture will be a real GL Texture under the hood
class TextureView {
public:
typedef Resource::Size Size;
typedef int Index;
BufferPointer _buffer;
Size _offset;
Size _size;
Element _element;
uint16 _stride;
TextureView() :
_buffer(NULL),
_offset(0),
_size(0),
_element(gpu::VEC3, gpu::UINT8, gpu::RGB),
_stride(1)
{};
TextureView(const Element& element) :
_buffer(NULL),
_offset(0),
_size(0),
_element(element),
_stride(uint16(element.getSize()))
{};
// create the BufferView and own the Buffer
TextureView(Buffer* newBuffer, const Element& element) :
_buffer(newBuffer),
_offset(0),
_size(newBuffer->getSize()),
_element(element),
_stride(uint16(element.getSize()))
{};
TextureView(const BufferPointer& buffer, const Element& element) :
_buffer(buffer),
_offset(0),
_size(buffer->getSize()),
_element(element),
_stride(uint16(element.getSize()))
{};
TextureView(const BufferPointer& buffer, Size offset, Size size, const Element& element) :
_buffer(buffer),
_offset(offset),
_size(size),
_element(element),
_stride(uint16(element.getSize()))
{};
~TextureView() {}
TextureView(const TextureView& view) = default;
TextureView& operator=(const TextureView& view) = default;
};
};
#endif

327
libraries/gpu/src/gpu/Texture.cpp Executable file
View file

@ -0,0 +1,327 @@
//
// Texture.cpp
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 1/17/2015.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Texture.h"
#include <math.h>
#include <QDebug>
using namespace gpu;
Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) :
_sysmem(size, bytes),
_format(format) {
}
Texture::Pixels::~Pixels() {
}
void Texture::Storage::assignTexture(Texture* texture) {
_texture = texture;
}
Stamp Texture::Storage::getStamp(uint16 level) const {
PixelsPointer mip = getMip(level);
if (mip) {
return mip->_sysmem.getStamp();
}
return 0;
}
void Texture::Storage::reset() {
_mips.clear();
}
Texture::PixelsPointer Texture::Storage::editMip(uint16 level) {
if (level < _mips.size()) {
return _mips[level];
}
return PixelsPointer();
}
const Texture::PixelsPointer Texture::Storage::getMip(uint16 level) const {
if (level < _mips.size()) {
return _mips[level];
}
return PixelsPointer();
}
bool Texture::Storage::isMipAvailable(uint16 level) const {
PixelsPointer mip = getMip(level);
return (mip && mip->_sysmem.getSize());
}
bool Texture::Storage::allocateMip(uint16 level) {
bool changed = false;
if (level >= _mips.size()) {
_mips.resize(level+1, PixelsPointer());
changed = true;
}
if (!_mips[level]) {
_mips[level] = PixelsPointer(new Pixels());
changed = true;
}
return changed;
}
bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes) {
// Ok we should be able to do that...
allocateMip(level);
_mips[level]->_format = format;
Size allocated = _mips[level]->_sysmem.setData(size, bytes);
return allocated == size;
}
Texture* Texture::create1D(const Element& texelFormat, uint16 width) {
return create(TEX_1D, texelFormat, width, 1, 1, 1, 1);
}
Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height) {
return create(TEX_2D, texelFormat, width, height, 1, 1, 1);
}
Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth) {
return create(TEX_3D, texelFormat, width, height, depth, 1, 1);
}
Texture* Texture::createCube(const Element& texelFormat, uint16 width) {
return create(TEX_CUBE, texelFormat, width, width, 1, 1, 1);
}
Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices)
{
Texture* tex = new Texture();
tex->_storage.reset(new Storage());
tex->_storage->_texture = tex;
tex->_type = type;
tex->_maxMip = 0;
tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices);
return tex;
}
Texture* Texture::createFromStorage(Storage* storage) {
Texture* tex = new Texture();
tex->_storage.reset(storage);
storage->assignTexture(tex);
return tex;
}
Texture::Texture():
Resource(),
_storage(),
_stamp(0),
_size(0),
_width(1),
_height(1),
_depth(1),
_numSamples(1),
_numSlices(1),
_maxMip(0),
_type(TEX_1D),
_autoGenerateMips(false),
_defined(false)
{
}
Texture::~Texture()
{
}
Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) {
if (width && height && depth && numSamples && numSlices) {
bool changed = false;
if ( _type != type) {
_type = type;
changed = true;
}
if (_numSlices != numSlices) {
_numSlices = numSlices;
changed = true;
}
numSamples = evalNumSamplesUsed(numSamples);
if ((_type >= TEX_2D) && (_numSamples != numSamples)) {
_numSamples = numSamples;
changed = true;
}
if (_width != width) {
_width = width;
changed = true;
}
if ((_type >= TEX_2D) && (_height != height)) {
_height = height;
changed = true;
}
if ((_type >= TEX_3D) && (_depth != depth)) {
_depth = depth;
changed = true;
}
// Evaluate the new size with the new format
const int DIM_SIZE[] = {1, 1, 1, 6};
int size = DIM_SIZE[_type] *_width * _height * _depth * _numSamples * texelFormat.getSize();
// If size change then we need to reset
if (changed || (size != getSize())) {
_size = size;
_storage->reset();
_stamp++;
}
// TexelFormat might have change, but it's mostly interpretation
if (texelFormat != _texelFormat) {
_texelFormat = texelFormat;
_stamp++;
}
// Here the Texture has been fully defined from the gpu point of view (size and format)
_defined = true;
} else {
_stamp++;
}
return _size;
}
Texture::Size Texture::resize1D(uint16 width, uint16 numSamples) {
return resize(TEX_1D, getTexelFormat(), width, 1, 1, numSamples, 1);
}
Texture::Size Texture::resize2D(uint16 width, uint16 height, uint16 numSamples) {
return resize(TEX_2D, getTexelFormat(), width, height, 1, numSamples, 1);
}
Texture::Size Texture::resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples) {
return resize(TEX_3D, getTexelFormat(), width, height, depth, numSamples, 1);
}
Texture::Size Texture::resizeCube(uint16 width, uint16 numSamples) {
return resize(TEX_CUBE, getTexelFormat(), width, 1, 1, numSamples, 1);
}
Texture::Size Texture::reformat(const Element& texelFormat) {
return resize(_type, texelFormat, getWidth(), getHeight(), getDepth(), getNumSamples(), getNumSlices());
}
bool Texture::isColorRenderTarget() const {
return (_texelFormat.getSemantic() == gpu::RGBA);
}
bool Texture::isDepthStencilRenderTarget() const {
return (_texelFormat.getSemantic() == gpu::DEPTH) || (_texelFormat.getSemantic() == gpu::DEPTH_STENCIL);
}
uint16 Texture::evalDimNumMips(uint16 size) {
double largerDim = size;
double val = log(largerDim)/log(2.0);
return 1 + (uint16) val;
}
// The number mips that the texture could have if all existed
// = log2(max(width, height, depth))
uint16 Texture::evalNumMips() const {
double largerDim = std::max(std::max(_width, _height), _depth);
double val = log(largerDim)/log(2.0);
return 1 + (uint16) val;
}
uint16 Texture::maxMip() const {
return _maxMip;
}
bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes) {
// Check that level accessed make sense
if (level != 0) {
if (_autoGenerateMips) {
return false;
}
if (level >= evalNumMips()) {
return false;
}
}
// THen check that the mem buffer passed make sense with its format
if (size == evalStoredMipSize(level, format)) {
_storage->assignMipData(level, format, size, bytes);
_stamp++;
return true;
}
return false;
}
uint16 Texture::autoGenerateMips(uint16 maxMip) {
_autoGenerateMips = true;
_maxMip = std::min((uint16) (evalNumMips() - 1), maxMip);
_stamp++;
return _maxMip;
}
uint16 Texture::getStoredMipWidth(uint16 level) const {
PixelsPointer mip = accessStoredMip(level);
if (mip && mip->_sysmem.getSize()) {
return evalMipWidth(level);
}
return 0;
}
uint16 Texture::getStoredMipHeight(uint16 level) const {
PixelsPointer mip = accessStoredMip(level);
if (mip && mip->_sysmem.getSize()) {
return evalMipHeight(level);
}
return 0;
}
uint16 Texture::getStoredMipDepth(uint16 level) const {
PixelsPointer mip = accessStoredMip(level);
if (mip && mip->_sysmem.getSize()) {
return evalMipDepth(level);
}
return 0;
}
uint32 Texture::getStoredMipNumTexels(uint16 level) const {
PixelsPointer mip = accessStoredMip(level);
if (mip && mip->_sysmem.getSize()) {
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level);
}
return 0;
}
uint32 Texture::getStoredMipSize(uint16 level) const {
PixelsPointer mip = accessStoredMip(level);
if (mip && mip->_sysmem.getSize()) {
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize();
}
return 0;
}
uint16 Texture::evalNumSamplesUsed(uint16 numSamplesTried) {
uint16 sample = numSamplesTried;
if (numSamplesTried <= 1)
sample = 1;
else if (numSamplesTried < 4)
sample = 2;
else if (numSamplesTried < 8)
sample = 4;
else if (numSamplesTried < 16)
sample = 8;
else
sample = 8;
return sample;
}

255
libraries/gpu/src/gpu/Texture.h Executable file
View file

@ -0,0 +1,255 @@
//
// Texture.h
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 1/16/2015.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_Texture_h
#define hifi_gpu_Texture_h
#include "Resource.h"
#include <memory>
namespace gpu {
class Texture : public Resource {
public:
class Pixels {
public:
Pixels() {}
Pixels(const Pixels& pixels) = default;
Pixels(const Element& format, Size size, const Byte* bytes);
~Pixels();
Sysmem _sysmem;
Element _format;
};
typedef QSharedPointer< Pixels > PixelsPointer;
class Storage {
public:
Storage() {}
virtual ~Storage() {}
virtual void reset();
virtual PixelsPointer editMip(uint16 level);
virtual const PixelsPointer getMip(uint16 level) const;
virtual Stamp getStamp(uint16 level) const;
virtual bool allocateMip(uint16 level);
virtual bool assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes);
virtual bool isMipAvailable(uint16 level) const;
protected:
Texture* _texture;
std::vector<PixelsPointer> _mips;
virtual void assignTexture(Texture* tex);
friend class Texture;
};
enum Type {
TEX_1D = 0,
TEX_2D,
TEX_3D,
TEX_CUBE,
};
static Texture* create1D(const Element& texelFormat, uint16 width);
static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height);
static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth);
static Texture* createCube(const Element& texelFormat, uint16 width);
static Texture* createFromStorage(Storage* storage);
Texture(const Texture& buf); // deep copy of the sysmem texture
Texture& operator=(const Texture& buf); // deep copy of the sysmem texture
~Texture();
const Stamp getStamp() const { return _stamp; }
const Stamp getDataStamp(uint16 level = 0) const { return _storage->getStamp(level); }
// The size in bytes of data stored in the texture
Size getSize() const { return _size; }
// Resize, unless auto mips mode would destroy all the sub mips
Size resize1D(uint16 width, uint16 numSamples);
Size resize2D(uint16 width, uint16 height, uint16 numSamples);
Size resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples);
Size resizeCube(uint16 width, uint16 numSamples);
// Reformat, unless auto mips mode would destroy all the sub mips
Size reformat(const Element& texelFormat);
// Size and format
Type getType() const { return _type; }
bool isColorRenderTarget() const;
bool isDepthStencilRenderTarget() const;
const Element& getTexelFormat() const { return _texelFormat; }
bool hasBorder() const { return false; }
uint16 getWidth() const { return _width; }
uint16 getHeight() const { return _height; }
uint16 getDepth() const { return _depth; }
uint32 getRowPitch() const { return getWidth() * getTexelFormat().getSize(); }
uint32 getNumTexels() const { return _width * _height * _depth; }
uint16 getNumSlices() const { return _numSlices; }
uint16 getNumSamples() const { return _numSamples; }
// NumSamples can only have certain values based on the hw
static uint16 evalNumSamplesUsed(uint16 numSamplesTried);
// Mips size evaluation
// The number mips that a dimension could haves
// = 1 + log2(size)
static uint16 evalDimNumMips(uint16 size);
// The number mips that the texture could have if all existed
// = 1 + log2(max(width, height, depth))
uint16 evalNumMips() const;
// Eval the size that the mips level SHOULD have
// not the one stored in the Texture
uint16 evalMipWidth(uint16 level) const { return std::max(_width >> level, 1); }
uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); }
uint16 evalMipDepth(uint16 level) const { return std::max(_depth >> level, 1); }
uint32 evalMipNumTexels(uint16 level) const { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); }
uint32 evalMipSize(uint16 level) const { return evalMipNumTexels(level) * getTexelFormat().getSize(); }
uint32 evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); }
uint32 evalTotalSize() const {
uint32 size = 0;
uint16 minMipLevel = 0;
uint16 maxMipLevel = maxMip();
for (uint16 l = minMipLevel; l <= maxMipLevel; l++) {
size += evalMipSize(l);
}
return size * getNumSlices();
}
// max mip is in the range [ 1 if no sub mips, log2(max(width, height, depth))]
// if autoGenerateMip is on => will provide the maxMIp level specified
// else provide the deepest mip level provided through assignMip
uint16 maxMip() const;
// Generate the mips automatically
// But the sysmem version is not available
// Only works for the standard formats
// Specify the maximum Mip level available
// 0 is the default one
// 1 is the first level
// ...
// nbMips - 1 is the last mip level
//
// If -1 then all the mips are generated
//
// Return the totalnumber of mips that will be available
uint16 autoGenerateMips(uint16 maxMip);
bool isAutogenerateMips() const { return _autoGenerateMips; }
// Managing Storage and mips
// Manually allocate the mips down until the specified maxMip
// this is just allocating the sysmem version of it
// in case autoGen is on, this doesn't allocate
// Explicitely assign mip data for a certain level
// If Bytes is NULL then simply allocate the space so mip sysmem can be accessed
bool assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes);
// Access the the sub mips
bool isStoredMipAvailable(uint16 level) const { return _storage->isMipAvailable(level); }
const PixelsPointer accessStoredMip(uint16 level) const { return _storage->getMip(level); }
// access sizes for the stored mips
uint16 getStoredMipWidth(uint16 level) const;
uint16 getStoredMipHeight(uint16 level) const;
uint16 getStoredMipDepth(uint16 level) const;
uint32 getStoredMipNumTexels(uint16 level) const;
uint32 getStoredMipSize(uint16 level) const;
bool isDefined() const { return _defined; }
protected:
std::unique_ptr< Storage > _storage;
Stamp _stamp;
uint32 _size;
Element _texelFormat;
uint16 _width;
uint16 _height;
uint16 _depth;
uint16 _numSamples;
uint16 _numSlices;
uint16 _maxMip;
Type _type;
bool _autoGenerateMips;
bool _defined;
static Texture* create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
Texture();
Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
mutable GPUObject* _gpuObject = NULL;
// This shouldn't be used by anything else than the Backend class with the proper casting.
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
GPUObject* getGPUObject() const { return _gpuObject; }
friend class Backend;
};
typedef QSharedPointer<Texture> TexturePointer;
typedef std::vector< TexturePointer > Textures;
// TODO: For now TextureView works with Buffer as a place holder for the Texture.
// The overall logic should be about the same except that the Texture will be a real GL Texture under the hood
class TextureView {
public:
typedef Resource::Size Size;
TexturePointer _texture = TexturePointer(NULL);
uint16 _subresource = 0;
Element _element = Element(gpu::VEC4, gpu::UINT8, gpu::RGBA);
TextureView() {};
TextureView(const Element& element) :
_element(element)
{};
// create the TextureView and own the Texture
TextureView(Texture* newTexture, const Element& element) :
_texture(newTexture),
_subresource(0),
_element(element)
{};
TextureView(const TexturePointer& texture, const Element& element) :
_texture(texture),
_subresource(0),
_element(element)
{};
~TextureView() {}
TextureView(const TextureView& view) = default;
TextureView& operator=(const TextureView& view) = default;
};
};
#endif

View file

@ -17,6 +17,7 @@
#include <glm/glm.hpp>
#include "gpu/Resource.h"
#include "gpu/Texture.h"
namespace model {
typedef gpu::BufferView UniformBufferView;

View file

@ -9,27 +9,15 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QNetworkDiskCache>
#include <QStandardPaths>
#include <QThreadStorage>
#include "NetworkAccessManager.h"
const qint64 MAXIMUM_CACHE_SIZE = 10737418240; // 10GB
QThreadStorage<QNetworkAccessManager*> networkAccessManagers;
QNetworkAccessManager& NetworkAccessManager::getInstance() {
if (!networkAccessManagers.hasLocalData()) {
QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager();
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
QNetworkDiskCache* cache = new QNetworkDiskCache();
cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE);
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache");
networkAccessManager->setCache(cache);
networkAccessManagers.setLocalData(networkAccessManager);
networkAccessManagers.setLocalData(new QNetworkAccessManager());
}
return *networkAccessManagers.localData();

View file

@ -15,6 +15,7 @@
#include "BulletUtil.h"
#include "EntityMotionState.h"
#include "PhysicsEngine.h"
#include "PhysicsHelpers.h"
QSet<EntityItem*>* _outgoingEntityList;

View file

@ -14,6 +14,7 @@
#include "BulletUtil.h"
#include "ObjectMotionState.h"
#include "PhysicsEngine.h"
#include "PhysicsHelpers.h"
const float DEFAULT_FRICTION = 0.5f;
const float MAX_FRICTION = 10.0f;
@ -107,6 +108,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) {
if (_sentFrame == 0) {
_sentPosition = bulletToGLM(_body->getWorldTransform().getOrigin());
_sentVelocity = bulletToGLM(_body->getLinearVelocity());
_sentRotation = bulletToGLM(_body->getWorldTransform().getRotation());
_sentAngularVelocity = bulletToGLM(_body->getAngularVelocity());
_sentFrame = simulationFrame;
return false;
@ -118,7 +120,8 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) {
glm::vec3 wasAngularVelocity = _sentAngularVelocity;
#endif
float dt = (float)(simulationFrame - _sentFrame) * PHYSICS_ENGINE_FIXED_SUBSTEP;
int numFrames = simulationFrame - _sentFrame;
float dt = (float)(numFrames) * PHYSICS_ENGINE_FIXED_SUBSTEP;
_sentFrame = simulationFrame;
bool isActive = _body->isActive();
@ -170,16 +173,16 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) {
if (glm::length2(_sentAngularVelocity) > 0.0f) {
// compute rotation error
_sentAngularVelocity *= powf(1.0f - _angularDamping, dt);
float spin = glm::length(_sentAngularVelocity);
const float MIN_SPIN = 1.0e-4f;
if (spin > MIN_SPIN) {
glm::vec3 axis = _sentAngularVelocity / spin;
_sentRotation = glm::normalize(glm::angleAxis(dt * spin, axis) * _sentRotation);
float attenuation = powf(1.0f - _angularDamping, dt);
_sentAngularVelocity *= attenuation;
// Bullet caps the effective rotation velocity inside its rotation integration step, therefore
// we must integrate with the same algorithm and timestep in order achieve similar results.
for (int i = 0; i < numFrames; ++i) {
_sentRotation = glm::normalize(computeBulletRotationStep(_sentAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _sentRotation);
}
}
const float MIN_ROTATION_DOT = 0.98f;
const float MIN_ROTATION_DOT = 0.99f; // 0.99 dot threshold coresponds to about 16 degrees of slop
glm::quat actualRotation = bulletToGLM(worldTrans.getRotation());
#ifdef WANT_DEBUG

View file

@ -11,6 +11,7 @@
#include "PhysicsEngine.h"
#include "ShapeInfoUtil.h"
#include "PhysicsHelpers.h"
#include "ThreadSafeDynamicsWorld.h"
static uint32_t _numSubsteps;
@ -29,23 +30,27 @@ PhysicsEngine::~PhysicsEngine() {
// begin EntitySimulation overrides
void PhysicsEngine::updateEntitiesInternal(const quint64& now) {
// NOTE: the grand order of operations is:
// (1) relay incoming changes
// (2) step simulation
// (3) synchronize outgoing motion states
// (4) send outgoing packets
// this is step (4)
QSet<ObjectMotionState*>::iterator stateItr = _outgoingPackets.begin();
while (stateItr != _outgoingPackets.end()) {
ObjectMotionState* state = *stateItr;
if (state->doesNotNeedToSendUpdate()) {
stateItr = _outgoingPackets.erase(stateItr);
} else if (state->shouldSendUpdate(_numSubsteps)) {
state->sendUpdate(_entityPacketSender, _numSubsteps);
++stateItr;
} else {
++stateItr;
// no need to send updates unless the physics simulation has actually stepped
if (_lastNumSubstepsAtUpdateInternal != _numSubsteps) {
_lastNumSubstepsAtUpdateInternal = _numSubsteps;
// NOTE: the grand order of operations is:
// (1) relay incoming changes
// (2) step simulation
// (3) synchronize outgoing motion states
// (4) send outgoing packets
// this is step (4)
QSet<ObjectMotionState*>::iterator stateItr = _outgoingPackets.begin();
while (stateItr != _outgoingPackets.end()) {
ObjectMotionState* state = *stateItr;
if (state->doesNotNeedToSendUpdate()) {
stateItr = _outgoingPackets.erase(stateItr);
} else if (state->shouldSendUpdate(_numSubsteps)) {
state->sendUpdate(_entityPacketSender, _numSubsteps);
++stateItr;
} else {
++stateItr;
}
}
}
}

View file

@ -14,8 +14,6 @@
#include <stdint.h>
const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f;
#include <QSet>
#include <btBulletDynamicsCommon.h>
@ -114,6 +112,7 @@ private:
ContactMap _contactMap;
uint32_t _numContactFrames = 0;
uint32_t _lastNumSubstepsAtUpdateInternal = 0;
};
#endif // hifi_PhysicsEngine_h

View file

@ -59,7 +59,7 @@ vec3 evalDirectionalColor(float shadowAttenuation, vec3 position, vec3 normal, v
// Diffuse Lighting
float diffuseDot = dot(normal, gl_LightSource[0].position.xyz);
float facingLight = step(0.0, diffuseDot) * shadowAttenuation;
vec3 diffuseColor = diffuse * (gl_FrontLightModelProduct.sceneColor.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuseDot * facingLight));
vec3 diffuseColor = diffuse * (gl_FrontLightProduct[0].diffuse.rgb * (diffuseDot * facingLight));
// compute the specular multiplier (sans exponent)
float specularPower = facingLight * max(0.0,

View file

@ -211,7 +211,7 @@ void GeometryCache::renderSphere(float radius, int slices, int stacks, const glm
const int NORMALS_SLOT = 1;
const int COLOR_SLOT = 2;
gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ), 0);
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
@ -404,7 +404,7 @@ void GeometryCache::renderGrid(int xDivisions, int yDivisions, const glm::vec4&
const int COLOR_SLOT = 1;
gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::POS_XYZ), 0);
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
@ -515,7 +515,7 @@ void GeometryCache::renderGrid(int x, int y, int width, int height, int rows, in
const int COLOR_SLOT = 1;
gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::POS_XYZ), 0);
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
@ -561,7 +561,7 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, con
details.streamFormat = streamFormat;
details.stream = stream;
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::POS_XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
@ -623,7 +623,7 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec3>& points, con
details.streamFormat = streamFormat;
details.stream = stream;
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
@ -777,7 +777,7 @@ void GeometryCache::renderSolidCube(float size, const glm::vec4& color) {
const int COLOR_SLOT = 2;
gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ), 0);
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
@ -867,7 +867,7 @@ void GeometryCache::renderWireCube(float size, const glm::vec4& color) {
const int VERTICES_SLOT = 0;
const int COLOR_SLOT = 1;
gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ), 0);
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
gpu::BufferView verticesView(verticesBuffer, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
@ -930,7 +930,7 @@ void GeometryCache::renderBevelCornersRect(int x, int y, int width, int height,
details.streamFormat = streamFormat;
details.stream = stream;
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::POS_XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
@ -1038,7 +1038,7 @@ void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxC
details.streamFormat = streamFormat;
details.stream = stream;
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::POS_XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
@ -1123,7 +1123,7 @@ void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxC
details.streamFormat = streamFormat;
details.stream = stream;
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::POS_XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET);
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
@ -1211,7 +1211,7 @@ void GeometryCache::renderQuad(const glm::vec3& minCorner, const glm::vec3& maxC
details.streamFormat = streamFormat;
details.stream = stream;
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
@ -1548,7 +1548,7 @@ void GeometryCache::renderLine(const glm::vec3& p1, const glm::vec3& p2,
details.streamFormat = streamFormat;
details.stream = stream;
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
@ -1640,7 +1640,7 @@ void GeometryCache::renderLine(const glm::vec2& p1, const glm::vec2& p2,
details.streamFormat = streamFormat;
details.stream = stream;
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
@ -2179,7 +2179,7 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
int channelNum = 0;
networkMesh._vertexFormat = gpu::Stream::FormatPointer(new gpu::Stream::Format());
networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ), 0);
networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
if (mesh.normals.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.tangents.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.colors.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
@ -2213,7 +2213,7 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
int channelNum = 0;
networkMesh._vertexFormat = gpu::Stream::FormatPointer(new gpu::Stream::Format());
networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ));
networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.normals.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.tangents.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.colors.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));

View file

@ -812,6 +812,15 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
GLBATCH(glCullFace)(GL_BACK);
}
GLBATCH(glActiveTexture)(GL_TEXTURE0 + 1);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0 + 2);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0 + 3);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
// deactivate vertex arrays after drawing
GLBATCH(glDisableClientState)(GL_NORMAL_ARRAY);
GLBATCH(glDisableClientState)(GL_VERTEX_ARRAY);
@ -1768,6 +1777,17 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
GLBATCH(glCullFace)(GL_BACK);
}
GLBATCH(glActiveTexture)(GL_TEXTURE0 + 1);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0 + 2);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0 + 3);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
// deactivate vertex arrays after drawing
GLBATCH(glDisableClientState)(GL_NORMAL_ARRAY);
GLBATCH(glDisableClientState)(GL_VERTEX_ARRAY);
@ -2224,7 +2244,10 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f
}
GLBATCH(glUseProgram)(activeProgram->programId());
GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold);
if ((activeLocations->alphaThreshold > -1) && (mode != SHADOW_RENDER_MODE)) {
GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold);
}
}
int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold,
@ -2348,7 +2371,7 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
}
}
GLBATCH(glPushMatrix)();
// GLBATCH(glPushMatrix)();
const MeshState& state = _meshStates.at(i);
if (state.clusterMatrices.size() > 1) {
@ -2385,7 +2408,7 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
// apply material properties
if (mode == SHADOW_RENDER_MODE) {
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
/// GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
} else {
if (lastMaterialID != part.materialID) {
@ -2414,9 +2437,12 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
}
static bool showDiffuse = true;
if (showDiffuse && diffuseMap) {
GLBATCH(glBindTexture)(GL_TEXTURE_2D, diffuseMap->getID());
// GLBATCH(glBindTexture)(GL_TEXTURE_2D, diffuseMap->getID());
batch.setUniformTexture(0, diffuseMap->getGPUTexture());
} else {
GLBATCH(glBindTexture)(GL_TEXTURE_2D, textureCache->getWhiteTextureID());
// GLBATCH(glBindTexture)(GL_TEXTURE_2D, textureCache->getWhiteTextureID());
batch.setUniformTexture(0, textureCache->getWhiteTexture());
}
if (locations->texcoordMatrices >= 0) {
@ -2431,19 +2457,16 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
}
if (!mesh.tangents.isEmpty()) {
GLBATCH(glActiveTexture)(GL_TEXTURE1);
Texture* normalMap = networkPart.normalTexture.data();
GLBATCH(glBindTexture)(GL_TEXTURE_2D, !normalMap ?
textureCache->getBlueTextureID() : normalMap->getID());
GLBATCH(glActiveTexture)(GL_TEXTURE0);
batch.setUniformTexture(1, !normalMap ?
textureCache->getBlueTexture() : normalMap->getGPUTexture());
}
if (locations->specularTextureUnit >= 0) {
GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->specularTextureUnit);
Texture* specularMap = networkPart.specularTexture.data();
GLBATCH(glBindTexture)(GL_TEXTURE_2D, !specularMap ?
textureCache->getWhiteTextureID() : specularMap->getID());
GLBATCH(glActiveTexture)(GL_TEXTURE0);
batch.setUniformTexture(locations->specularTextureUnit, !specularMap ?
textureCache->getWhiteTexture() : specularMap->getGPUTexture());
}
if (args) {
@ -2460,11 +2483,9 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
float emissiveScale = part.emissiveParams.y;
GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale);
GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->emissiveTextureUnit);
Texture* emissiveMap = networkPart.emissiveTexture.data();
GLBATCH(glBindTexture)(GL_TEXTURE_2D, !emissiveMap ?
textureCache->getWhiteTextureID() : emissiveMap->getID());
GLBATCH(glActiveTexture)(GL_TEXTURE0);
batch.setUniformTexture(locations->emissiveTextureUnit, !emissiveMap ?
textureCache->getWhiteTexture() : emissiveMap->getGPUTexture());
}
lastMaterialID = part.materialID;
@ -2489,27 +2510,6 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
args->_quadsRendered += part.quadIndices.size() / INDICES_PER_QUAD;
}
}
if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) {
GLBATCH(glActiveTexture)(GL_TEXTURE1);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0);
}
if (locations->specularTextureUnit >= 0) {
GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->specularTextureUnit);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0);
}
if (locations->emissiveTextureUnit >= 0) {
GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->emissiveTextureUnit);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0);
}
GLBATCH(glPopMatrix)();
}
return meshPartsRendered;

View file

@ -167,7 +167,7 @@ TextRenderer::TextRenderer(const Properties& properties) :
_glyphsStream(new gpu::BufferStream()),
_numGlyphsBatched(0)
{
_glyphsStreamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::POS_XYZ), 0);
_glyphsStreamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
const int NUM_POS_COORDS = 2;
const int VERTEX_TEXCOORD_OFFSET = NUM_POS_COORDS * sizeof(float);
_glyphsStreamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET);

View file

@ -25,10 +25,12 @@
#include "TextureCache.h"
#include "gpu/GLBackend.h"
TextureCache::TextureCache() :
_permutationNormalTextureID(0),
_whiteTextureID(0),
_blueTextureID(0),
_permutationNormalTexture(0),
_whiteTexture(0),
_blueTexture(0),
_primaryDepthTextureID(0),
_primaryNormalTextureID(0),
_primarySpecularTextureID(0),
@ -44,12 +46,7 @@ TextureCache::TextureCache() :
}
TextureCache::~TextureCache() {
if (_permutationNormalTextureID != 0) {
glDeleteTextures(1, &_permutationNormalTextureID);
}
if (_whiteTextureID != 0) {
glDeleteTextures(1, &_whiteTextureID);
}
if (_primaryFramebufferObject) {
glDeleteTextures(1, &_primaryDepthTextureID);
glDeleteTextures(1, &_primaryNormalTextureID);
@ -124,11 +121,9 @@ const int permutation[256] =
#define USE_CHRIS_NOISE 1
GLuint TextureCache::getPermutationNormalTextureID() {
if (_permutationNormalTextureID == 0) {
glGenTextures(1, &_permutationNormalTextureID);
glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID);
const gpu::TexturePointer& TextureCache::getPermutationNormalTexture() {
if (_permutationNormalTexture.isNull()) {
// the first line consists of random permutation offsets
unsigned char data[256 * 2 * 3];
#if (USE_CHRIS_NOISE==1)
@ -148,12 +143,14 @@ GLuint TextureCache::getPermutationNormalTextureID() {
data[i + 1] = ((randvec.y + 1.0f) / 2.0f) * 255.0f;
data[i + 2] = ((randvec.z + 1.0f) / 2.0f) * 255.0f;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
_permutationNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB), 256, 2));
_permutationNormalTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(data), data);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
return _permutationNormalTextureID;
return _permutationNormalTexture;
}
const unsigned char OPAQUE_WHITE[] = { 0xFF, 0xFF, 0xFF, 0xFF };
@ -166,24 +163,20 @@ static void loadSingleColorTexture(const unsigned char* color) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
GLuint TextureCache::getWhiteTextureID() {
if (_whiteTextureID == 0) {
glGenTextures(1, &_whiteTextureID);
glBindTexture(GL_TEXTURE_2D, _whiteTextureID);
loadSingleColorTexture(OPAQUE_WHITE);
glBindTexture(GL_TEXTURE_2D, 0);
const gpu::TexturePointer& TextureCache::getWhiteTexture() {
if (_whiteTexture.isNull()) {
_whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1));
_whiteTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_WHITE);
}
return _whiteTextureID;
return _whiteTexture;
}
GLuint TextureCache::getBlueTextureID() {
if (_blueTextureID == 0) {
glGenTextures(1, &_blueTextureID);
glBindTexture(GL_TEXTURE_2D, _blueTextureID);
loadSingleColorTexture(OPAQUE_BLUE);
glBindTexture(GL_TEXTURE_2D, 0);
const gpu::TexturePointer& TextureCache::getBlueTexture() {
if (_blueTexture.isNull()) {
_blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1));
_blueTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(OPAQUE_BLUE), OPAQUE_BLUE);
}
return _blueTextureID;
return _blueTexture;
}
/// Extra data for creating textures.
@ -375,11 +368,13 @@ QOpenGLFramebufferObject* TextureCache::createFramebufferObject() {
}
Texture::Texture() {
glGenTextures(1, &_id);
}
Texture::~Texture() {
glDeleteTextures(1, &_id);
}
GLuint Texture::getID() const {
return gpu::GLBackend::getTextureID(_gpuTexture);
}
NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content) :
@ -394,7 +389,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArr
}
// default to white/blue/black
glBindTexture(GL_TEXTURE_2D, getID());
/* glBindTexture(GL_TEXTURE_2D, getID());
switch (type) {
case NORMAL_TEXTURE:
loadSingleColorTexture(OPAQUE_BLUE);
@ -413,7 +408,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArr
break;
}
glBindTexture(GL_TEXTURE_2D, 0);
*/
// if we have content, load it after we have our self pointer
if (!content.isEmpty()) {
_startedLoading = true;
@ -546,18 +541,20 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo
finishedLoading(true);
imageLoaded(image);
glBindTexture(GL_TEXTURE_2D, getID());
if (image.hasAlphaChannel()) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0,
GL_RGB, GL_UNSIGNED_BYTE, image.constBits());
if ((_width > 0) && (_height > 0)) {
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
if (image.hasAlphaChannel()) {
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
}
_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height()));
_gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
_gpuTexture->autoGenerateMips(-1);
}
// generate mipmaps
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
}
void NetworkTexture::imageLoaded(const QImage& image) {
@ -585,18 +582,18 @@ QSharedPointer<Texture> DilatableNetworkTexture::getDilatedTexture(float dilatio
path.addEllipse(QPointF(_image.width() / 2.0, _image.height() / 2.0), radius, radius);
painter.fillPath(path, Qt::black);
painter.end();
glBindTexture(GL_TEXTURE_2D, texture->getID());
bool isLinearRGB = true;// (_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
if (dilatedImage.hasAlphaChannel()) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits());
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dilatedImage.width(), dilatedImage.height(), 0,
GL_RGB, GL_UNSIGNED_BYTE, dilatedImage.constBits());
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::BGRA));
}
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
texture->_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, dilatedImage.width(), dilatedImage.height()));
texture->_gpuTexture->assignStoredMip(0, formatMip, dilatedImage.byteCount(), dilatedImage.constBits());
texture->_gpuTexture->autoGenerateMips(-1);
}
_dilatedTextures.insert(dilation, texture);

View file

@ -13,6 +13,7 @@
#define hifi_TextureCache_h
#include <gpu/GPUConfig.h>
#include <gpu/Texture.h>
#include <QImage>
#include <QMap>
@ -45,13 +46,13 @@ public:
/// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture
/// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and
/// the second, a set of random unit vectors to be used as noise gradients.
GLuint getPermutationNormalTextureID();
const gpu::TexturePointer& getPermutationNormalTexture();
/// Returns the ID of an opaque white texture (useful for a default).
GLuint getWhiteTextureID();
/// Returns an opaque white texture (useful for a default).
const gpu::TexturePointer& getWhiteTexture();
/// Returns the ID of a pale blue texture (useful for a normal map).
GLuint getBlueTextureID();
/// Returns the a pale blue texture (useful for a normal map).
const gpu::TexturePointer& getBlueTexture();
/// Loads a texture from the specified URL.
NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE, bool dilatable = false,
@ -100,10 +101,10 @@ private:
friend class DilatableNetworkTexture;
QOpenGLFramebufferObject* createFramebufferObject();
GLuint _permutationNormalTextureID;
GLuint _whiteTextureID;
GLuint _blueTextureID;
gpu::TexturePointer _permutationNormalTexture;
gpu::TexturePointer _whiteTexture;
gpu::TexturePointer _blueTexture;
QHash<QUrl, QWeakPointer<NetworkTexture> > _dilatableNetworkTextures;
@ -124,15 +125,19 @@ private:
/// A simple object wrapper for an OpenGL texture.
class Texture {
public:
friend class TextureCache;
friend class DilatableNetworkTexture;
Texture();
~Texture();
GLuint getID() const { return _id; }
GLuint getID() const;
const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; }
protected:
gpu::TexturePointer _gpuTexture;
private:
GLuint _id;
};
/// A texture loaded from the network.
@ -165,8 +170,9 @@ protected:
virtual void imageLoaded(const QImage& image);
private:
TextureType _type;
private:
bool _translucent;
QColor _averageColor;
int _originalWidth;

View file

@ -0,0 +1,58 @@
//
// PhysicsHelpers.cpp
// libraries/shared/src
//
// Created by Andrew Meadows 2015.01.27
// Unless otherwise copyrighted: Copyright 2015 High Fidelity, Inc.
//
// Unless otherwise licensced: Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "PhysicsHelpers.h"
#include "SharedUtil.h"
// This chunk of code was copied from Bullet-2.82, so we include the Bullet license here:
/*
* Bullet Continuous Collision Detection and Physics Library
* Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it freely,
* subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but
* is not required.
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Copied and modified from LinearMath/btTransformUtil.h by AndrewMeadows on 2015.01.27.
* */
glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float timeStep) {
// Bullet uses an exponential map approximation technique to integrate rotation.
// The reason for this is to make it easy to compute the derivative of angular motion for various consraints.
// Here we reproduce the same approximation so that our extrapolations agree well with Bullet's integration.
//
// Exponential map
// google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia
float speed = glm::length(angularVelocity);
// limit the angular motion because the exponential approximation fails for large steps
const float ANGULAR_MOTION_THRESHOLD = 0.5f * PI_OVER_TWO;
if (speed * timeStep > ANGULAR_MOTION_THRESHOLD) {
speed = ANGULAR_MOTION_THRESHOLD / timeStep;
}
glm::vec3 axis = angularVelocity;
if (speed < 0.001f) {
// use Taylor's expansions of sync function
axis *= (0.5f * timeStep - (timeStep * timeStep * timeStep) * (0.020833333333f * speed * speed));
} else {
// sync(speed) = sin(c * speed)/t
axis *= (sinf(0.5f * speed * timeStep) / speed );
}
return glm::quat(cosf(0.5f * speed * timeStep), axis.x, axis.y, axis.z);
}

View file

@ -0,0 +1,23 @@
//
// PhysicsHelpers.h
// libraries/shared/src
//
// Created by Andrew Meadows 2015.01.27
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_PhysicsHelpers_h
#define hifi_PhysicsHelpers_h
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f;
// return incremental rotation (Bullet-style) caused by angularVelocity over timeStep
glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float timeStep);
#endif // hifi_PhysicsHelpers_h