mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 09:23:17 +02:00
Merge pull request #4400 from samcake/temp0
Introduce gpu::Shader, Pipeline and State
This commit is contained in:
commit
5cced9fc66
35 changed files with 2695 additions and 525 deletions
|
@ -2941,6 +2941,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
|||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity());
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalAtmosphere(skyStage->getAtmosphere());
|
||||
|
||||
PROFILE_RANGE("DeferredLighting");
|
||||
PerformanceTimer perfTimer("lighting");
|
||||
|
|
|
@ -25,7 +25,8 @@ Batch::Batch() :
|
|||
_buffers(),
|
||||
_textures(),
|
||||
_streamFormats(),
|
||||
_transforms()
|
||||
_transforms(),
|
||||
_pipelines()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -42,6 +43,7 @@ void Batch::clear() {
|
|||
_textures.clear();
|
||||
_streamFormats.clear();
|
||||
_transforms.clear();
|
||||
_pipelines.clear();
|
||||
}
|
||||
|
||||
uint32 Batch::cacheResource(Resource* res) {
|
||||
|
@ -159,6 +161,12 @@ void Batch::setProjectionTransform(const Mat4& proj) {
|
|||
_params.push_back(cacheData(sizeof(Mat4), &proj));
|
||||
}
|
||||
|
||||
void Batch::setPipeline(const PipelinePointer& pipeline) {
|
||||
ADD_COMMAND(setPipeline);
|
||||
|
||||
_params.push_back(_pipelines.cache(pipeline));
|
||||
}
|
||||
|
||||
void Batch::setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size) {
|
||||
ADD_COMMAND(setUniformBuffer);
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "Stream.h"
|
||||
#include "Texture.h"
|
||||
|
||||
#include "Pipeline.h"
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
#include "nvToolsExt.h"
|
||||
class ProfileRange {
|
||||
|
@ -96,7 +98,9 @@ public:
|
|||
void setViewTransform(const Transform& view);
|
||||
void setProjectionTransform(const Mat4& proj);
|
||||
|
||||
// Shader Stage
|
||||
// Pipeline Stage
|
||||
void setPipeline(const PipelinePointer& pipeline);
|
||||
|
||||
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
|
||||
|
||||
|
@ -164,6 +168,7 @@ public:
|
|||
COMMAND_setViewTransform,
|
||||
COMMAND_setProjectionTransform,
|
||||
|
||||
COMMAND_setPipeline,
|
||||
COMMAND_setUniformBuffer,
|
||||
COMMAND_setUniformTexture,
|
||||
|
||||
|
@ -281,6 +286,7 @@ public:
|
|||
typedef Cache<TexturePointer>::Vector TextureCaches;
|
||||
typedef Cache<Stream::FormatPointer>::Vector StreamFormatCaches;
|
||||
typedef Cache<Transform>::Vector TransformCaches;
|
||||
typedef Cache<PipelinePointer>::Vector PipelineCaches;
|
||||
|
||||
typedef unsigned char Byte;
|
||||
typedef std::vector<Byte> Bytes;
|
||||
|
@ -320,6 +326,7 @@ public:
|
|||
TextureCaches _textures;
|
||||
StreamFormatCaches _streamFormats;
|
||||
TransformCaches _transforms;
|
||||
PipelineCaches _pipelines;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
|
|
@ -10,3 +10,14 @@
|
|||
//
|
||||
#include "Context.h"
|
||||
|
||||
// this include should disappear! as soon as the gpu::Context is in place
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
|
||||
if (shader.isProgram()) {
|
||||
return GLBackend::makeProgram(shader, bindings);
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "Resource.h"
|
||||
#include "Texture.h"
|
||||
#include "Shader.h"
|
||||
#include "Pipeline.h"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
|
@ -46,25 +48,39 @@ public:
|
|||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Buffer& buffer, T* bo) {
|
||||
buffer.setGPUObject(reinterpret_cast<GPUObject*>(bo));
|
||||
buffer.setGPUObject(bo);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Buffer& buffer) {
|
||||
return reinterpret_cast<T*>(buffer.getGPUObject());
|
||||
}
|
||||
|
||||
void syncGPUObject(const Buffer& buffer);
|
||||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Texture& texture, T* to) {
|
||||
texture.setGPUObject(reinterpret_cast<GPUObject*>(to));
|
||||
texture.setGPUObject(to);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Texture& texture) {
|
||||
return reinterpret_cast<T*>(texture.getGPUObject());
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Shader& shader, T* so) {
|
||||
shader.setGPUObject(so);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Shader& shader) {
|
||||
return reinterpret_cast<T*>(shader.getGPUObject());
|
||||
}
|
||||
|
||||
void syncGPUObject(const Texture& texture);
|
||||
template< typename T >
|
||||
static void setGPUObject(const Pipeline& pipeline, T* po) {
|
||||
pipeline.setGPUObject(po);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Pipeline& pipeline) {
|
||||
return reinterpret_cast<T*>(pipeline.getGPUObject());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -78,8 +94,17 @@ public:
|
|||
|
||||
void enqueueBatch(Batch& batch);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// This function can only be called by "static Shader::makeProgram()"
|
||||
// makeProgramShader(...) make a program shader ready to be used in a Batch.
|
||||
// It compiles the sub shaders, link them and defines the Slots and their bindings.
|
||||
// If the shader passed is not a program, nothing happens.
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
|
||||
|
||||
friend class Shader;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ enum Type {
|
|||
NUINT8,
|
||||
|
||||
NUM_TYPES,
|
||||
|
||||
BOOL = UINT8,
|
||||
};
|
||||
// Array providing the size in bytes for a given scalar type
|
||||
static const int TYPE_SIZE[NUM_TYPES] = {
|
||||
|
@ -81,9 +83,9 @@ enum Dimension {
|
|||
VEC2,
|
||||
VEC3,
|
||||
VEC4,
|
||||
MAT2,
|
||||
MAT3,
|
||||
MAT4,
|
||||
|
||||
NUM_DIMENSIONS,
|
||||
};
|
||||
// Count (of scalars) in an Element for a given Dimension
|
||||
|
@ -92,8 +94,9 @@ static const int DIMENSION_COUNT[NUM_DIMENSIONS] = {
|
|||
2,
|
||||
3,
|
||||
4,
|
||||
4,
|
||||
9,
|
||||
16
|
||||
16,
|
||||
};
|
||||
|
||||
// Semantic of an Element
|
||||
|
@ -118,6 +121,13 @@ enum Semantic {
|
|||
SRGBA,
|
||||
SBGRA,
|
||||
|
||||
UNIFORM,
|
||||
UNIFORM_BUFFER,
|
||||
SAMPLER,
|
||||
SAMPLER_MULTISAMPLE,
|
||||
SAMPLER_SHADOW,
|
||||
|
||||
|
||||
NUM_SEMANTICS,
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::GLBackend::do_setViewTransform),
|
||||
(&::gpu::GLBackend::do_setProjectionTransform),
|
||||
|
||||
(&::gpu::GLBackend::do_setPipeline),
|
||||
(&::gpu::GLBackend::do_setUniformBuffer),
|
||||
(&::gpu::GLBackend::do_setUniformTexture),
|
||||
|
||||
|
@ -71,7 +72,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
|
||||
GLBackend::GLBackend() :
|
||||
_input(),
|
||||
_transform()
|
||||
_transform(),
|
||||
_pipeline()
|
||||
{
|
||||
initTransform();
|
||||
}
|
||||
|
@ -134,6 +136,7 @@ void GLBackend::checkGLError() {
|
|||
void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
|
||||
updateInput();
|
||||
updateTransform();
|
||||
updatePipeline();
|
||||
|
||||
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
|
||||
GLenum mode = _primitiveToGLmode[primitiveType];
|
||||
|
@ -147,6 +150,7 @@ void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
|
|||
void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) {
|
||||
updateInput();
|
||||
updateTransform();
|
||||
updatePipeline();
|
||||
|
||||
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
|
||||
GLenum mode = _primitiveToGLmode[primitiveType];
|
||||
|
@ -167,389 +171,6 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) {
|
|||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) {
|
||||
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);
|
||||
|
||||
if (format != _input._format) {
|
||||
_input._format = format;
|
||||
_input._invalidFormat = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) {
|
||||
Offset stride = batch._params[paramOffset + 0]._uint;
|
||||
Offset offset = batch._params[paramOffset + 1]._uint;
|
||||
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
uint32 channel = batch._params[paramOffset + 3]._uint;
|
||||
|
||||
if (channel < getNumInputBuffers()) {
|
||||
_input._buffers[channel] = buffer;
|
||||
_input._bufferOffsets[channel] = offset;
|
||||
_input._bufferStrides[channel] = stride;
|
||||
_input._buffersState.set(channel);
|
||||
}
|
||||
}
|
||||
|
||||
#define SUPPORT_LEGACY_OPENGL
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
static const int NUM_CLASSIC_ATTRIBS = Stream::TANGENT;
|
||||
static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = {
|
||||
GL_VERTEX_ARRAY,
|
||||
GL_NORMAL_ARRAY,
|
||||
GL_COLOR_ARRAY,
|
||||
GL_TEXTURE_COORD_ARRAY
|
||||
};
|
||||
#endif
|
||||
|
||||
void GLBackend::updateInput() {
|
||||
if (_input._invalidFormat || _input._buffersState.any()) {
|
||||
|
||||
if (_input._invalidFormat) {
|
||||
InputStageState::ActivationCache newActivation;
|
||||
|
||||
// Check expected activation
|
||||
if (_input._format) {
|
||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
||||
for (Stream::Format::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
|
||||
const Stream::Attribute& attrib = (*it).second;
|
||||
newActivation.set(attrib._slot);
|
||||
}
|
||||
}
|
||||
|
||||
// Manage Activation what was and what is expected now
|
||||
for (unsigned int i = 0; i < newActivation.size(); i++) {
|
||||
bool newState = newActivation[i];
|
||||
if (newState != _input._attributeActivation[i]) {
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
if (i < NUM_CLASSIC_ATTRIBS) {
|
||||
if (newState) {
|
||||
glEnableClientState(attributeSlotToClassicAttribName[i]);
|
||||
}
|
||||
else {
|
||||
glDisableClientState(attributeSlotToClassicAttribName[i]);
|
||||
}
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
if (newState) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_input._attributeActivation.flip(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we need to bind the buffers and assign the attrib pointers
|
||||
if (_input._format) {
|
||||
const Buffers& buffers = _input._buffers;
|
||||
const Offsets& offsets = _input._bufferOffsets;
|
||||
const Offsets& strides = _input._bufferStrides;
|
||||
|
||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
||||
|
||||
for (Stream::Format::ChannelMap::const_iterator channelIt = _input._format->getChannels().begin();
|
||||
channelIt != _input._format->getChannels().end();
|
||||
channelIt++) {
|
||||
const Stream::Format::ChannelMap::value_type::second_type& channel = (*channelIt).second;
|
||||
if ((*channelIt).first < buffers.size()) {
|
||||
int bufferNum = (*channelIt).first;
|
||||
|
||||
if (_input._buffersState.test(bufferNum) || _input._invalidFormat) {
|
||||
GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum]));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
CHECK_GL_ERROR();
|
||||
_input._buffersState[bufferNum] = false;
|
||||
|
||||
for (unsigned int i = 0; i < channel._slots.size(); i++) {
|
||||
const Stream::Attribute& attrib = attributes.at(channel._slots[i]);
|
||||
GLuint slot = attrib._slot;
|
||||
GLuint count = attrib._element.getDimensionCount();
|
||||
GLenum type = _elementTypeToGLType[attrib._element.getType()];
|
||||
GLuint stride = strides[bufferNum];
|
||||
GLuint pointer = attrib._offset + offsets[bufferNum];
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
if (slot < NUM_CLASSIC_ATTRIBS) {
|
||||
switch (slot) {
|
||||
case Stream::POSITION:
|
||||
glVertexPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::NORMAL:
|
||||
glNormalPointer(type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::COLOR:
|
||||
glColorPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::TEXCOORD:
|
||||
glTexCoordPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
};
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
GLboolean isNormalized = attrib._element.isNormalized();
|
||||
glVertexAttribPointer(slot, count, type, isNormalized, stride,
|
||||
reinterpret_cast<GLvoid*>(pointer));
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// everything format related should be in sync now
|
||||
_input._invalidFormat = false;
|
||||
}
|
||||
|
||||
/* TODO: Fancy version GL4.4
|
||||
if (_needInputFormatUpdate) {
|
||||
|
||||
InputActivationCache newActivation;
|
||||
|
||||
// Assign the vertex format required
|
||||
if (_inputFormat) {
|
||||
const StreamFormat::AttributeMap& attributes = _inputFormat->getAttributes();
|
||||
for (StreamFormat::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
|
||||
const StreamFormat::Attribute& attrib = (*it).second;
|
||||
newActivation.set(attrib._slot);
|
||||
glVertexAttribFormat(
|
||||
attrib._slot,
|
||||
attrib._element.getDimensionCount(),
|
||||
_elementTypeToGLType[attrib._element.getType()],
|
||||
attrib._element.isNormalized(),
|
||||
attrib._stride);
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
// Manage Activation what was and what is expected now
|
||||
for (int i = 0; i < newActivation.size(); i++) {
|
||||
bool newState = newActivation[i];
|
||||
if (newState != _inputAttributeActivation[i]) {
|
||||
if (newState) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
_inputAttributeActivation.flip(i);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_needInputFormatUpdate = false;
|
||||
}
|
||||
|
||||
if (_needInputStreamUpdate) {
|
||||
if (_inputStream) {
|
||||
const Stream::Buffers& buffers = _inputStream->getBuffers();
|
||||
const Stream::Offsets& offsets = _inputStream->getOffsets();
|
||||
const Stream::Strides& strides = _inputStream->getStrides();
|
||||
|
||||
for (int i = 0; i < buffers.size(); i++) {
|
||||
GLuint vbo = gpu::GLBackend::getBufferID((*buffers[i]));
|
||||
glBindVertexBuffer(i, vbo, offsets[i], strides[i]);
|
||||
}
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
_needInputStreamUpdate = false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) {
|
||||
_input._indexBufferType = (Type) batch._params[paramOffset + 2]._uint;
|
||||
BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);
|
||||
_input._indexBufferOffset = batch._params[paramOffset + 0]._uint;
|
||||
_input._indexBuffer = indexBuffer;
|
||||
if (indexBuffer) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer));
|
||||
} else {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
// Transform Stage
|
||||
|
||||
void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) {
|
||||
_transform._model = batch._transforms.get(batch._params[paramOffset]._uint);
|
||||
_transform._invalidModel = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) {
|
||||
_transform._view = batch._transforms.get(batch._params[paramOffset]._uint);
|
||||
_transform._invalidView = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) {
|
||||
memcpy(&_transform._projection, batch.editData(batch._params[paramOffset]._uint), sizeof(Mat4));
|
||||
_transform._invalidProj = true;
|
||||
}
|
||||
|
||||
void GLBackend::initTransform() {
|
||||
#if defined(Q_OS_WIN)
|
||||
glGenBuffers(1, &_transform._transformObjectBuffer);
|
||||
glGenBuffers(1, &_transform._transformCameraBuffer);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformObjectBuffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformCameraBuffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW);
|
||||
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::killTransform() {
|
||||
#if defined(Q_OS_WIN)
|
||||
glDeleteBuffers(1, &_transform._transformObjectBuffer);
|
||||
glDeleteBuffers(1, &_transform._transformCameraBuffer);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
void GLBackend::updateTransform() {
|
||||
// Check all the dirty flags and update the state accordingly
|
||||
if (_transform._invalidProj) {
|
||||
_transform._transformCamera._projection = _transform._projection;
|
||||
}
|
||||
|
||||
if (_transform._invalidView) {
|
||||
_transform._view.getInverseMatrix(_transform._transformCamera._view);
|
||||
_transform._view.getMatrix(_transform._transformCamera._viewInverse);
|
||||
}
|
||||
|
||||
if (_transform._invalidModel) {
|
||||
_transform._model.getMatrix(_transform._transformObject._model);
|
||||
_transform._model.getInverseMatrix(_transform._transformObject._modelInverse);
|
||||
}
|
||||
|
||||
if (_transform._invalidView || _transform._invalidProj) {
|
||||
Mat4 viewUntranslated = _transform._transformCamera._view;
|
||||
viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
_transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated;
|
||||
}
|
||||
|
||||
if (_transform._invalidView || _transform._invalidProj) {
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_transform._invalidModel) {
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformObjectBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._transformObjectBuffer);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _transform._transformCameraBuffer);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
|
||||
// Do it again for fixed pipeline until we can get rid of it
|
||||
if (_transform._invalidProj) {
|
||||
if (_transform._lastMode != GL_PROJECTION) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
_transform._lastMode = GL_PROJECTION;
|
||||
}
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&_transform._projection));
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
if (_transform._invalidModel || _transform._invalidView) {
|
||||
if (!_transform._model.isIdentity()) {
|
||||
if (_transform._lastMode != GL_MODELVIEW) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
_transform._lastMode = GL_MODELVIEW;
|
||||
}
|
||||
Transform::Mat4 modelView;
|
||||
if (!_transform._view.isIdentity()) {
|
||||
Transform mvx;
|
||||
Transform::inverseMult(mvx, _transform._view, _transform._model);
|
||||
mvx.getMatrix(modelView);
|
||||
} else {
|
||||
_transform._model.getMatrix(modelView);
|
||||
}
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
|
||||
} else {
|
||||
if (!_transform._view.isIdentity()) {
|
||||
if (_transform._lastMode != GL_MODELVIEW) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
_transform._lastMode = GL_MODELVIEW;
|
||||
}
|
||||
Transform::Mat4 modelView;
|
||||
_transform._view.getInverseMatrix(modelView);
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
|
||||
} else {
|
||||
// TODO: eventually do something about the matrix when neither view nor model is specified?
|
||||
// glLoadIdentity();
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Flags are clean
|
||||
_transform._invalidView = _transform._invalidProj = _transform._invalidModel = false;
|
||||
}
|
||||
|
||||
void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 3]._uint;
|
||||
BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
|
||||
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
|
||||
#if defined(Q_OS_MAC)
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
|
||||
// NOT working so we ll stick to the uniform float array until we move to core profile
|
||||
// GLuint bo = getBufferID(*uniformBuffer);
|
||||
//glUniformBufferEXT(_shader._program, slot, bo);
|
||||
#elif defined(Q_OS_WIN)
|
||||
GLuint bo = getBufferID(*uniformBuffer);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize);
|
||||
#else
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
#endif
|
||||
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
|
||||
|
@ -740,8 +361,10 @@ void Batch::_glUseProgram(GLuint program) {
|
|||
}
|
||||
void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) {
|
||||
|
||||
_shader._program = batch._params[paramOffset]._uint;
|
||||
glUseProgram(_shader._program);
|
||||
_pipeline._program = batch._params[paramOffset]._uint;
|
||||
// for this call we still want to execute the glUseProgram in the order of the glCOmmand to avoid any issue
|
||||
_pipeline._invalidProgram = false;
|
||||
glUseProgram(_pipeline._program);
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
@ -998,49 +621,3 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) {
|
|||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
GLBackend::GLBuffer::GLBuffer() :
|
||||
_stamp(0),
|
||||
_buffer(0),
|
||||
_size(0)
|
||||
{}
|
||||
|
||||
GLBackend::GLBuffer::~GLBuffer() {
|
||||
if (_buffer != 0) {
|
||||
glDeleteBuffers(1, &_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::syncGPUObject(const Buffer& buffer) {
|
||||
GLBuffer* object = Backend::getGPUObject<GLBackend::GLBuffer>(buffer);
|
||||
|
||||
if (object && (object->_stamp == buffer.getSysmem().getStamp())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// need to have a gpu object?
|
||||
if (!object) {
|
||||
object = new GLBuffer();
|
||||
glGenBuffers(1, &object->_buffer);
|
||||
CHECK_GL_ERROR();
|
||||
Backend::setGPUObject(buffer, object);
|
||||
}
|
||||
|
||||
// Now let's update the content of the bo with the sysmem version
|
||||
// TODO: in the future, be smarter about when to actually upload the glBO version based on the data that did change
|
||||
//if () {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, object->_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
object->_stamp = buffer.getSysmem().getStamp();
|
||||
object->_size = buffer.getSysmem().getSize();
|
||||
//}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLuint GLBackend::getBufferID(const Buffer& buffer) {
|
||||
GLBackend::syncGPUObject(buffer);
|
||||
return Backend::getGPUObject<GLBackend::GLBuffer>(buffer)->_buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ public:
|
|||
|
||||
static void checkGLError();
|
||||
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
|
||||
|
||||
|
||||
class GLBuffer : public GPUObject {
|
||||
|
@ -44,7 +45,7 @@ public:
|
|||
GLBuffer();
|
||||
~GLBuffer();
|
||||
};
|
||||
static void syncGPUObject(const Buffer& buffer);
|
||||
static GLBuffer* syncGPUObject(const Buffer& buffer);
|
||||
static GLuint getBufferID(const Buffer& buffer);
|
||||
|
||||
class GLTexture : public GPUObject {
|
||||
|
@ -57,9 +58,33 @@ public:
|
|||
GLTexture();
|
||||
~GLTexture();
|
||||
};
|
||||
static void syncGPUObject(const Texture& texture);
|
||||
static GLTexture* syncGPUObject(const Texture& texture);
|
||||
static GLuint getTextureID(const TexturePointer& texture);
|
||||
|
||||
class GLShader : public GPUObject {
|
||||
public:
|
||||
GLuint _shader;
|
||||
GLuint _program;
|
||||
|
||||
GLuint _transformCameraSlot = -1;
|
||||
GLuint _transformObjectSlot = -1;
|
||||
|
||||
GLShader();
|
||||
~GLShader();
|
||||
};
|
||||
static GLShader* syncGPUObject(const Shader& shader);
|
||||
static GLuint getShaderID(const ShaderPointer& shader);
|
||||
|
||||
|
||||
class GLPipeline : public GPUObject {
|
||||
public:
|
||||
GLShader* _program;
|
||||
|
||||
GLPipeline();
|
||||
~GLPipeline();
|
||||
};
|
||||
static GLPipeline* syncGPUObject(const Pipeline& pipeline);
|
||||
|
||||
static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
|
||||
static const int MAX_NUM_INPUT_BUFFERS = 16;
|
||||
|
||||
|
@ -145,18 +170,24 @@ protected:
|
|||
_lastMode(GL_TEXTURE) {}
|
||||
} _transform;
|
||||
|
||||
// Shader Stage
|
||||
// Pipeline Stage
|
||||
void do_setPipeline(Batch& batch, uint32 paramOffset);
|
||||
void do_setUniformBuffer(Batch& batch, uint32 paramOffset);
|
||||
void do_setUniformTexture(Batch& batch, uint32 paramOffset);
|
||||
|
||||
void updateShader();
|
||||
struct ShaderStageState {
|
||||
void updatePipeline();
|
||||
struct PipelineStageState {
|
||||
|
||||
PipelinePointer _pipeline;
|
||||
GLuint _program;
|
||||
bool _invalidProgram;
|
||||
|
||||
ShaderStageState() :
|
||||
_program(0) {}
|
||||
} _shader;
|
||||
PipelineStageState() :
|
||||
_pipeline(),
|
||||
_program(0),
|
||||
_invalidProgram(false)
|
||||
{}
|
||||
} _pipeline;
|
||||
|
||||
|
||||
// TODO: As long as we have gl calls explicitely issued from interface
|
||||
|
|
66
libraries/gpu/src/gpu/GLBackendBuffer.cpp
Executable file
66
libraries/gpu/src/gpu/GLBackendBuffer.cpp
Executable file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// GLBackendBuffer.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/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"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
GLBackend::GLBuffer::GLBuffer() :
|
||||
_stamp(0),
|
||||
_buffer(0),
|
||||
_size(0)
|
||||
{}
|
||||
|
||||
GLBackend::GLBuffer::~GLBuffer() {
|
||||
if (_buffer != 0) {
|
||||
glDeleteBuffers(1, &_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) {
|
||||
GLBuffer* object = Backend::getGPUObject<GLBackend::GLBuffer>(buffer);
|
||||
|
||||
if (object && (object->_stamp == buffer.getSysmem().getStamp())) {
|
||||
return object;
|
||||
}
|
||||
|
||||
// need to have a gpu object?
|
||||
if (!object) {
|
||||
object = new GLBuffer();
|
||||
glGenBuffers(1, &object->_buffer);
|
||||
CHECK_GL_ERROR();
|
||||
Backend::setGPUObject(buffer, object);
|
||||
}
|
||||
|
||||
// Now let's update the content of the bo with the sysmem version
|
||||
// TODO: in the future, be smarter about when to actually upload the glBO version based on the data that did change
|
||||
//if () {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, object->_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
object->_stamp = buffer.getSysmem().getStamp();
|
||||
object->_size = buffer.getSysmem().getSize();
|
||||
//}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLuint GLBackend::getBufferID(const Buffer& buffer) {
|
||||
GLBuffer* bo = GLBackend::syncGPUObject(buffer);
|
||||
if (bo) {
|
||||
return bo->_buffer;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
223
libraries/gpu/src/gpu/GLBackendInput.cpp
Executable file
223
libraries/gpu/src/gpu/GLBackendInput.cpp
Executable file
|
@ -0,0 +1,223 @@
|
|||
//
|
||||
// GLBackendInput.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/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"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) {
|
||||
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);
|
||||
|
||||
if (format != _input._format) {
|
||||
_input._format = format;
|
||||
_input._invalidFormat = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) {
|
||||
Offset stride = batch._params[paramOffset + 0]._uint;
|
||||
Offset offset = batch._params[paramOffset + 1]._uint;
|
||||
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
uint32 channel = batch._params[paramOffset + 3]._uint;
|
||||
|
||||
if (channel < getNumInputBuffers()) {
|
||||
_input._buffers[channel] = buffer;
|
||||
_input._bufferOffsets[channel] = offset;
|
||||
_input._bufferStrides[channel] = stride;
|
||||
_input._buffersState.set(channel);
|
||||
}
|
||||
}
|
||||
|
||||
#define SUPPORT_LEGACY_OPENGL
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
static const int NUM_CLASSIC_ATTRIBS = Stream::TANGENT;
|
||||
static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = {
|
||||
GL_VERTEX_ARRAY,
|
||||
GL_NORMAL_ARRAY,
|
||||
GL_COLOR_ARRAY,
|
||||
GL_TEXTURE_COORD_ARRAY
|
||||
};
|
||||
#endif
|
||||
|
||||
void GLBackend::updateInput() {
|
||||
if (_input._invalidFormat || _input._buffersState.any()) {
|
||||
|
||||
if (_input._invalidFormat) {
|
||||
InputStageState::ActivationCache newActivation;
|
||||
|
||||
// Check expected activation
|
||||
if (_input._format) {
|
||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
||||
for (Stream::Format::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
|
||||
const Stream::Attribute& attrib = (*it).second;
|
||||
newActivation.set(attrib._slot);
|
||||
}
|
||||
}
|
||||
|
||||
// Manage Activation what was and what is expected now
|
||||
for (unsigned int i = 0; i < newActivation.size(); i++) {
|
||||
bool newState = newActivation[i];
|
||||
if (newState != _input._attributeActivation[i]) {
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
if (i < NUM_CLASSIC_ATTRIBS) {
|
||||
if (newState) {
|
||||
glEnableClientState(attributeSlotToClassicAttribName[i]);
|
||||
}
|
||||
else {
|
||||
glDisableClientState(attributeSlotToClassicAttribName[i]);
|
||||
}
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
if (newState) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_input._attributeActivation.flip(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we need to bind the buffers and assign the attrib pointers
|
||||
if (_input._format) {
|
||||
const Buffers& buffers = _input._buffers;
|
||||
const Offsets& offsets = _input._bufferOffsets;
|
||||
const Offsets& strides = _input._bufferStrides;
|
||||
|
||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
||||
|
||||
for (Stream::Format::ChannelMap::const_iterator channelIt = _input._format->getChannels().begin();
|
||||
channelIt != _input._format->getChannels().end();
|
||||
channelIt++) {
|
||||
const Stream::Format::ChannelMap::value_type::second_type& channel = (*channelIt).second;
|
||||
if ((*channelIt).first < buffers.size()) {
|
||||
int bufferNum = (*channelIt).first;
|
||||
|
||||
if (_input._buffersState.test(bufferNum) || _input._invalidFormat) {
|
||||
GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum]));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
CHECK_GL_ERROR();
|
||||
_input._buffersState[bufferNum] = false;
|
||||
|
||||
for (unsigned int i = 0; i < channel._slots.size(); i++) {
|
||||
const Stream::Attribute& attrib = attributes.at(channel._slots[i]);
|
||||
GLuint slot = attrib._slot;
|
||||
GLuint count = attrib._element.getDimensionCount();
|
||||
GLenum type = _elementTypeToGLType[attrib._element.getType()];
|
||||
GLuint stride = strides[bufferNum];
|
||||
GLuint pointer = attrib._offset + offsets[bufferNum];
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
if (slot < NUM_CLASSIC_ATTRIBS) {
|
||||
switch (slot) {
|
||||
case Stream::POSITION:
|
||||
glVertexPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::NORMAL:
|
||||
glNormalPointer(type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::COLOR:
|
||||
glColorPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::TEXCOORD:
|
||||
glTexCoordPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
};
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
GLboolean isNormalized = attrib._element.isNormalized();
|
||||
glVertexAttribPointer(slot, count, type, isNormalized, stride,
|
||||
reinterpret_cast<GLvoid*>(pointer));
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// everything format related should be in sync now
|
||||
_input._invalidFormat = false;
|
||||
}
|
||||
|
||||
/* TODO: Fancy version GL4.4
|
||||
if (_needInputFormatUpdate) {
|
||||
|
||||
InputActivationCache newActivation;
|
||||
|
||||
// Assign the vertex format required
|
||||
if (_inputFormat) {
|
||||
const StreamFormat::AttributeMap& attributes = _inputFormat->getAttributes();
|
||||
for (StreamFormat::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
|
||||
const StreamFormat::Attribute& attrib = (*it).second;
|
||||
newActivation.set(attrib._slot);
|
||||
glVertexAttribFormat(
|
||||
attrib._slot,
|
||||
attrib._element.getDimensionCount(),
|
||||
_elementTypeToGLType[attrib._element.getType()],
|
||||
attrib._element.isNormalized(),
|
||||
attrib._stride);
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
// Manage Activation what was and what is expected now
|
||||
for (int i = 0; i < newActivation.size(); i++) {
|
||||
bool newState = newActivation[i];
|
||||
if (newState != _inputAttributeActivation[i]) {
|
||||
if (newState) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
_inputAttributeActivation.flip(i);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_needInputFormatUpdate = false;
|
||||
}
|
||||
|
||||
if (_needInputStreamUpdate) {
|
||||
if (_inputStream) {
|
||||
const Stream::Buffers& buffers = _inputStream->getBuffers();
|
||||
const Stream::Offsets& offsets = _inputStream->getOffsets();
|
||||
const Stream::Strides& strides = _inputStream->getStrides();
|
||||
|
||||
for (int i = 0; i < buffers.size(); i++) {
|
||||
GLuint vbo = gpu::GLBackend::getBufferID((*buffers[i]));
|
||||
glBindVertexBuffer(i, vbo, offsets[i], strides[i]);
|
||||
}
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
_needInputStreamUpdate = false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) {
|
||||
_input._indexBufferType = (Type) batch._params[paramOffset + 2]._uint;
|
||||
BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);
|
||||
_input._indexBufferOffset = batch._params[paramOffset + 0]._uint;
|
||||
_input._indexBuffer = indexBuffer;
|
||||
if (indexBuffer) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer));
|
||||
} else {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
95
libraries/gpu/src/gpu/GLBackendPipeline.cpp
Executable file
95
libraries/gpu/src/gpu/GLBackendPipeline.cpp
Executable file
|
@ -0,0 +1,95 @@
|
|||
//
|
||||
// GLBackendPipeline.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/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"
|
||||
|
||||
#include "Format.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
GLBackend::GLPipeline::GLPipeline() :
|
||||
_program(nullptr)
|
||||
{}
|
||||
|
||||
GLBackend::GLPipeline::~GLPipeline() {
|
||||
_program = nullptr;
|
||||
}
|
||||
|
||||
GLBackend::GLPipeline* GLBackend::syncGPUObject(const Pipeline& pipeline) {
|
||||
GLPipeline* object = Backend::getGPUObject<GLBackend::GLPipeline>(pipeline);
|
||||
|
||||
// If GPU object already created then good
|
||||
if (object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) {
|
||||
PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
if (pipeline == _pipeline._pipeline) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto pipelineObject = syncGPUObject((*pipeline));
|
||||
if (!pipelineObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
_pipeline._pipeline = pipeline;
|
||||
_pipeline._program = pipelineObject->_program->_program;
|
||||
_pipeline._invalidProgram = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 3]._uint;
|
||||
BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
|
||||
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
|
||||
#if defined(Q_OS_MAC)
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
|
||||
// NOT working so we ll stick to the uniform float array until we move to core profile
|
||||
// GLuint bo = getBufferID(*uniformBuffer);
|
||||
//glUniformBufferEXT(_shader._program, slot, bo);
|
||||
#elif defined(Q_OS_WIN)
|
||||
GLuint bo = getBufferID(*uniformBuffer);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize);
|
||||
#else
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
#endif
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::updatePipeline() {
|
||||
if (_pipeline._invalidProgram) {
|
||||
glUseProgram(_pipeline._program);
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._invalidProgram = true;
|
||||
}
|
||||
}
|
||||
|
685
libraries/gpu/src/gpu/GLBackendShader.cpp
Executable file
685
libraries/gpu/src/gpu/GLBackendShader.cpp
Executable file
|
@ -0,0 +1,685 @@
|
|||
//
|
||||
// GLBackendShader.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 2/28/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"
|
||||
|
||||
#include "Format.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
GLBackend::GLShader::GLShader() :
|
||||
_shader(0),
|
||||
_program(0)
|
||||
{}
|
||||
|
||||
GLBackend::GLShader::~GLShader() {
|
||||
if (_shader != 0) {
|
||||
glDeleteShader(_shader);
|
||||
}
|
||||
if (_program != 0) {
|
||||
glDeleteProgram(_program);
|
||||
}
|
||||
}
|
||||
|
||||
void makeBindings(GLBackend::GLShader* shader) {
|
||||
if(!shader || !shader->_program) {
|
||||
return;
|
||||
}
|
||||
GLuint glprogram = shader->_program;
|
||||
GLint loc = -1;
|
||||
|
||||
//Check for gpu specific attribute slotBindings
|
||||
loc = glGetAttribLocation(glprogram, "position");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::POSITION, "position");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "normal");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "normal");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "color");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::COLOR, "color");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "texcoord");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "texcoord");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "tangent");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "tangent");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "texcoord1");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "texcoord1");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "clusterIndices");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "clusterIndices");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "clusterWeights");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "clusterWeights");
|
||||
}
|
||||
|
||||
// Link again to take into account the assigned attrib location
|
||||
glLinkProgram(glprogram);
|
||||
|
||||
GLint linked = 0;
|
||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||
if (!linked) {
|
||||
qDebug() << "GLShader::makeBindings - failed to link after assigning slotBindings?";
|
||||
}
|
||||
|
||||
// now assign the ubo binding, then DON't relink!
|
||||
|
||||
//Check for gpu specific uniform slotBindings
|
||||
#if defined(Q_OS_WIN)
|
||||
loc = glGetUniformBlockIndex(glprogram, "transformObjectBuffer");
|
||||
if (loc >= 0) {
|
||||
glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT);
|
||||
shader->_transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT;
|
||||
}
|
||||
|
||||
loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer");
|
||||
if (loc >= 0) {
|
||||
glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT);
|
||||
shader->_transformCameraSlot = gpu::TRANSFORM_OBJECT_SLOT;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GLBackend::GLShader* compileShader(const Shader& shader) {
|
||||
// Any GLSLprogram ? normally yes...
|
||||
const std::string& shaderSource = shader.getSource().getCode();
|
||||
if (shaderSource.empty()) {
|
||||
qDebug() << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Shader domain
|
||||
const GLenum SHADER_DOMAINS[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
|
||||
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
|
||||
|
||||
// Create the shader object
|
||||
GLuint glshader = glCreateShader(shaderDomain);
|
||||
if (!glshader) {
|
||||
qDebug() << "GLShader::compileShader - failed to create the gl shader object";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Assign the source
|
||||
const GLchar* srcstr = shaderSource.c_str();
|
||||
glShaderSource(glshader, 1, &srcstr, NULL);
|
||||
|
||||
// Compile !
|
||||
glCompileShader(glshader);
|
||||
|
||||
// check if shader compiled
|
||||
GLint compiled = 0;
|
||||
glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled);
|
||||
|
||||
// if compilation fails
|
||||
if (!compiled) {
|
||||
// save the source code to a temp file so we can debug easily
|
||||
/* std::ofstream filestream;
|
||||
filestream.open("debugshader.glsl");
|
||||
if (filestream.is_open()) {
|
||||
filestream << shaderSource->source;
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
GLint infoLength = 0;
|
||||
glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
|
||||
char* temp = new char[infoLength] ;
|
||||
glGetShaderInfoLog(glshader, infoLength, NULL, temp);
|
||||
|
||||
qDebug() << "GLShader::compileShader - failed to compile the gl shader object:";
|
||||
qDebug() << temp;
|
||||
|
||||
/*
|
||||
filestream.open("debugshader.glsl.info.txt");
|
||||
if (filestream.is_open()) {
|
||||
filestream << std::string(temp);
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
delete[] temp;
|
||||
|
||||
glDeleteShader(glshader);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLuint glprogram = 0;
|
||||
#ifdef SEPARATE_PROGRAM
|
||||
// so far so good, program is almost done, need to link:
|
||||
GLuint glprogram = glCreateProgram();
|
||||
if (!glprogram) {
|
||||
qDebug() << "GLShader::compileShader - failed to create the gl shader & gl program object";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
glProgramParameteri(glprogram, GL_PROGRAM_SEPARABLE, GL_TRUE);
|
||||
glAttachShader(glprogram, glshader);
|
||||
glLinkProgram(glprogram);
|
||||
|
||||
GLint linked = 0;
|
||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||
|
||||
if (!linked) {
|
||||
/*
|
||||
// save the source code to a temp file so we can debug easily
|
||||
std::ofstream filestream;
|
||||
filestream.open("debugshader.glsl");
|
||||
if (filestream.is_open()) {
|
||||
filestream << shaderSource->source;
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
GLint infoLength = 0;
|
||||
glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
|
||||
char* temp = new char[infoLength] ;
|
||||
glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
|
||||
|
||||
qDebug() << "GLShader::compileShader - failed to LINK the gl program object :";
|
||||
qDebug() << temp;
|
||||
|
||||
/*
|
||||
filestream.open("debugshader.glsl.info.txt");
|
||||
if (filestream.is_open()) {
|
||||
filestream << String(temp);
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
delete[] temp;
|
||||
|
||||
glDeleteShader(glshader);
|
||||
glDeleteProgram(glprogram);
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// So far so good, the shader is created successfully
|
||||
GLBackend::GLShader* object = new GLBackend::GLShader();
|
||||
object->_shader = glshader;
|
||||
object->_program = glprogram;
|
||||
|
||||
makeBindings(object);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
GLBackend::GLShader* compileProgram(const Shader& program) {
|
||||
if(!program.isProgram()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Let's go through every shaders and make sure they are ready to go
|
||||
std::vector< GLuint > shaderObjects;
|
||||
for (auto subShader : program.getShaders()) {
|
||||
GLuint so = GLBackend::getShaderID(subShader);
|
||||
if (!so) {
|
||||
qDebug() << "GLShader::compileProgram - One of the shaders of the program is not compiled?";
|
||||
return nullptr;
|
||||
}
|
||||
shaderObjects.push_back(so);
|
||||
}
|
||||
|
||||
// so far so good, program is almost done, need to link:
|
||||
GLuint glprogram = glCreateProgram();
|
||||
if (!glprogram) {
|
||||
qDebug() << "GLShader::compileProgram - failed to create the gl program object";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE);
|
||||
// Create the program from the sub shaders
|
||||
for (auto so : shaderObjects) {
|
||||
glAttachShader(glprogram, so);
|
||||
}
|
||||
|
||||
// Link!
|
||||
glLinkProgram(glprogram);
|
||||
|
||||
GLint linked = 0;
|
||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||
|
||||
if (!linked) {
|
||||
/*
|
||||
// save the source code to a temp file so we can debug easily
|
||||
std::ofstream filestream;
|
||||
filestream.open("debugshader.glsl");
|
||||
if (filestream.is_open()) {
|
||||
filestream << shaderSource->source;
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
GLint infoLength = 0;
|
||||
glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
|
||||
char* temp = new char[infoLength] ;
|
||||
glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
|
||||
|
||||
qDebug() << "GLShader::compileProgram - failed to LINK the gl program object :";
|
||||
qDebug() << temp;
|
||||
|
||||
/*
|
||||
filestream.open("debugshader.glsl.info.txt");
|
||||
if (filestream.is_open()) {
|
||||
filestream << std::string(temp);
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
delete[] temp;
|
||||
|
||||
glDeleteProgram(glprogram);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// So far so good, the program is created successfully
|
||||
GLBackend::GLShader* object = new GLBackend::GLShader();
|
||||
object->_shader = 0;
|
||||
object->_program = glprogram;
|
||||
|
||||
makeBindings(object);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
GLBackend::GLShader* GLBackend::syncGPUObject(const Shader& shader) {
|
||||
GLShader* object = Backend::getGPUObject<GLBackend::GLShader>(shader);
|
||||
|
||||
// If GPU object already created then good
|
||||
if (object) {
|
||||
return object;
|
||||
}
|
||||
// need to have a gpu object?
|
||||
if (shader.isProgram()) {
|
||||
GLShader* tempObject = compileProgram(shader);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
}
|
||||
} else if (shader.isDomain()) {
|
||||
GLShader* tempObject = compileShader(shader);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
GLuint GLBackend::getShaderID(const ShaderPointer& shader) {
|
||||
if (!shader) {
|
||||
return 0;
|
||||
}
|
||||
GLShader* object = GLBackend::syncGPUObject(*shader);
|
||||
if (object) {
|
||||
if (shader->isProgram()) {
|
||||
return object->_program;
|
||||
} else {
|
||||
return object->_shader;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class ElementResource {
|
||||
public:
|
||||
gpu::Element _element;
|
||||
uint16 _resource;
|
||||
|
||||
ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {}
|
||||
};
|
||||
|
||||
ElementResource getFormatFromGLUniform(GLenum gltype) {
|
||||
switch (gltype) {
|
||||
case GL_FLOAT: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
/*
|
||||
case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
*/
|
||||
case GL_INT: return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC2: return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC3: return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC4: return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_UNSIGNED_INT_VEC2: return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC3: return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC4: return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
#endif
|
||||
|
||||
case GL_BOOL: return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC2: return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC3: return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC4: return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
|
||||
|
||||
case GL_FLOAT_MAT2: return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_MAT3: return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_MAT4: return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
|
||||
/* {GL_FLOAT_MAT2x3 mat2x3},
|
||||
{GL_FLOAT_MAT2x4 mat2x4},
|
||||
{GL_FLOAT_MAT3x2 mat3x2},
|
||||
{GL_FLOAT_MAT3x4 mat3x4},
|
||||
{GL_FLOAT_MAT4x2 mat4x2},
|
||||
{GL_FLOAT_MAT4x3 mat4x3},
|
||||
{GL_DOUBLE_MAT2 dmat2},
|
||||
{GL_DOUBLE_MAT3 dmat3},
|
||||
{GL_DOUBLE_MAT4 dmat4},
|
||||
{GL_DOUBLE_MAT2x3 dmat2x3},
|
||||
{GL_DOUBLE_MAT2x4 dmat2x4},
|
||||
{GL_DOUBLE_MAT3x2 dmat3x2},
|
||||
{GL_DOUBLE_MAT3x4 dmat3x4},
|
||||
{GL_DOUBLE_MAT4x2 dmat4x2},
|
||||
{GL_DOUBLE_MAT4x3 dmat4x3},
|
||||
*/
|
||||
|
||||
case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D);
|
||||
|
||||
case GL_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
#endif
|
||||
|
||||
case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D);
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY);
|
||||
#endif
|
||||
|
||||
// {GL_SAMPLER_1D_SHADOW sampler1DShadow},
|
||||
// {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow},
|
||||
|
||||
// {GL_SAMPLER_BUFFER samplerBuffer},
|
||||
// {GL_SAMPLER_2D_RECT sampler2DRect},
|
||||
// {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow},
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
|
||||
// {GL_INT_SAMPLER_BUFFER isamplerBuffer},
|
||||
// {GL_INT_SAMPLER_2D_RECT isampler2DRect},
|
||||
|
||||
case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
#endif
|
||||
// {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer},
|
||||
// {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect},
|
||||
/*
|
||||
{GL_IMAGE_1D image1D},
|
||||
{GL_IMAGE_2D image2D},
|
||||
{GL_IMAGE_3D image3D},
|
||||
{GL_IMAGE_2D_RECT image2DRect},
|
||||
{GL_IMAGE_CUBE imageCube},
|
||||
{GL_IMAGE_BUFFER imageBuffer},
|
||||
{GL_IMAGE_1D_ARRAY image1DArray},
|
||||
{GL_IMAGE_2D_ARRAY image2DArray},
|
||||
{GL_IMAGE_2D_MULTISAMPLE image2DMS},
|
||||
{GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray},
|
||||
{GL_INT_IMAGE_1D iimage1D},
|
||||
{GL_INT_IMAGE_2D iimage2D},
|
||||
{GL_INT_IMAGE_3D iimage3D},
|
||||
{GL_INT_IMAGE_2D_RECT iimage2DRect},
|
||||
{GL_INT_IMAGE_CUBE iimageCube},
|
||||
{GL_INT_IMAGE_BUFFER iimageBuffer},
|
||||
{GL_INT_IMAGE_1D_ARRAY iimage1DArray},
|
||||
{GL_INT_IMAGE_2D_ARRAY iimage2DArray},
|
||||
{GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS},
|
||||
{GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray},
|
||||
{GL_UNSIGNED_INT_IMAGE_1D uimage1D},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D uimage2D},
|
||||
{GL_UNSIGNED_INT_IMAGE_3D uimage3D},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect},
|
||||
{GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot
|
||||
|
||||
{GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer},
|
||||
{GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray},
|
||||
{GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint}
|
||||
*/
|
||||
default:
|
||||
return ElementResource(Element(), Resource::BUFFER);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) {
|
||||
GLint uniformsCount = 0;
|
||||
|
||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
||||
|
||||
for (int i = 0; i < uniformsCount; i++) {
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar name[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
GLint size = 0;
|
||||
GLenum type = 0;
|
||||
glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
||||
GLint location = glGetUniformLocation(glprogram, name);
|
||||
const GLint INVALID_UNIFORM_LOCATION = -1;
|
||||
|
||||
// Try to make sense of the gltype
|
||||
auto elementResource = getFormatFromGLUniform(type);
|
||||
|
||||
// The uniform as a standard var type
|
||||
if (location != INVALID_UNIFORM_LOCATION) {
|
||||
if (elementResource._resource == Resource::BUFFER) {
|
||||
uniforms.insert(Shader::Slot(name, location, elementResource._element, elementResource._resource));
|
||||
} else {
|
||||
// For texture/Sampler, the location is the actual binding value
|
||||
GLint binding = -1;
|
||||
glGetUniformiv(glprogram, location, &binding);
|
||||
|
||||
auto requestedBinding = slotBindings.find(std::string(name));
|
||||
if (requestedBinding != slotBindings.end()) {
|
||||
if (binding != (*requestedBinding)._location) {
|
||||
binding = (*requestedBinding)._location;
|
||||
glUniform1i(location, binding);
|
||||
}
|
||||
}
|
||||
|
||||
textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
|
||||
samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uniformsCount;
|
||||
}
|
||||
|
||||
const GLint UNUSED_SLOT = -1;
|
||||
bool isUnusedSlot(GLint binding) {
|
||||
return (binding == UNUSED_SLOT);
|
||||
}
|
||||
|
||||
int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) {
|
||||
GLint buffersCount = 0;
|
||||
#if defined(Q_OS_WIN)
|
||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount);
|
||||
|
||||
// fast exit
|
||||
if (buffersCount == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLint maxNumUniformBufferSlots = 0;
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxNumUniformBufferSlots);
|
||||
std::vector<GLint> uniformBufferSlotMap(maxNumUniformBufferSlots, -1);
|
||||
|
||||
for (int i = 0; i < buffersCount; i++) {
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar name[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
GLint size = 0;
|
||||
GLenum type = 0;
|
||||
GLint binding = -1;
|
||||
|
||||
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length);
|
||||
glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, name);
|
||||
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_BINDING, &binding);
|
||||
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
|
||||
|
||||
GLuint blockIndex = glGetUniformBlockIndex(glprogram, name);
|
||||
|
||||
// CHeck if there is a requested binding for this block
|
||||
auto requestedBinding = slotBindings.find(std::string(name));
|
||||
if (requestedBinding != slotBindings.end()) {
|
||||
// If yes force it
|
||||
if (binding != (*requestedBinding)._location) {
|
||||
binding = (*requestedBinding)._location;
|
||||
glUniformBlockBinding(glprogram, blockIndex, binding);
|
||||
}
|
||||
} else if (binding == 0) {
|
||||
// If no binding was assigned then just do it finding a free slot
|
||||
auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), isUnusedSlot);
|
||||
if (slotIt != uniformBufferSlotMap.end()) {
|
||||
binding = slotIt - uniformBufferSlotMap.begin();
|
||||
glUniformBlockBinding(glprogram, blockIndex, binding);
|
||||
} else {
|
||||
// This should neve happen, an active ubo cannot find an available slot among the max available?!
|
||||
binding = -1;
|
||||
}
|
||||
}
|
||||
// If binding is valid record it
|
||||
if (binding >= 0) {
|
||||
uniformBufferSlotMap[binding] = blockIndex;
|
||||
}
|
||||
|
||||
Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER);
|
||||
buffers.insert(Shader::Slot(name, binding, element, Resource::BUFFER));
|
||||
}
|
||||
#endif
|
||||
return buffersCount;
|
||||
}
|
||||
|
||||
int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) {
|
||||
GLint inputsCount = 0;
|
||||
|
||||
glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount);
|
||||
|
||||
for (int i = 0; i < inputsCount; i++) {
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar name[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
GLint size = 0;
|
||||
GLenum type = 0;
|
||||
glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
||||
|
||||
GLint binding = glGetAttribLocation(glprogram, name);
|
||||
|
||||
auto elementResource = getFormatFromGLUniform(type);
|
||||
inputs.insert(Shader::Slot(name, binding, elementResource._element, -1));
|
||||
}
|
||||
|
||||
return inputsCount;
|
||||
}
|
||||
|
||||
int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) {
|
||||
/* GLint outputsCount = 0;
|
||||
|
||||
glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount);
|
||||
|
||||
for (int i = 0; i < inputsCount; i++) {
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar name[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
GLint size = 0;
|
||||
GLenum type = 0;
|
||||
glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
||||
|
||||
auto element = getFormatFromGLUniform(type);
|
||||
outputs.insert(Shader::Slot(name, i, element));
|
||||
}
|
||||
*/
|
||||
return 0; //inputsCount;
|
||||
}
|
||||
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
|
||||
|
||||
// First make sure the Shader has been compiled
|
||||
GLShader* object = GLBackend::syncGPUObject(shader);
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (object->_program) {
|
||||
Shader::SlotSet buffers;
|
||||
makeUniformBlockSlots(object->_program, slotBindings, buffers);
|
||||
|
||||
Shader::SlotSet uniforms;
|
||||
Shader::SlotSet textures;
|
||||
Shader::SlotSet samplers;
|
||||
makeUniformSlots(object->_program, slotBindings, uniforms, textures, samplers);
|
||||
|
||||
Shader::SlotSet inputs;
|
||||
makeInputSlots(object->_program, slotBindings, inputs);
|
||||
|
||||
Shader::SlotSet outputs;
|
||||
makeOutputSlots(object->_program, slotBindings, outputs);
|
||||
|
||||
shader.defineSlots(uniforms, buffers, textures, samplers, inputs, outputs);
|
||||
|
||||
} else if (object->_shader) {
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
void GLBackend::syncGPUObject(const Texture& texture) {
|
||||
GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
||||
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(texture);
|
||||
|
||||
// If GPU object already created and in sync
|
||||
|
@ -232,14 +232,14 @@ void GLBackend::syncGPUObject(const Texture& texture) {
|
|||
// 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;
|
||||
return object;
|
||||
} 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;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// need to have a gpu object?
|
||||
|
@ -320,6 +320,8 @@ void GLBackend::syncGPUObject(const Texture& texture) {
|
|||
qDebug() << "GLBackend::syncGPUObject(const Texture&) case for Texture Type " << texture.getType() << " not supported";
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
|
@ -328,8 +330,7 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture) {
|
|||
if (!texture) {
|
||||
return 0;
|
||||
}
|
||||
GLBackend::syncGPUObject(*texture);
|
||||
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texture);
|
||||
GLTexture* object = GLBackend::syncGPUObject(*texture);
|
||||
if (object) {
|
||||
return object->_texture;
|
||||
} else {
|
||||
|
|
156
libraries/gpu/src/gpu/GLBackendTransform.cpp
Executable file
156
libraries/gpu/src/gpu/GLBackendTransform.cpp
Executable file
|
@ -0,0 +1,156 @@
|
|||
//
|
||||
// GLBackendTransform.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/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"
|
||||
|
||||
#include "Format.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
// Transform Stage
|
||||
|
||||
void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) {
|
||||
_transform._model = batch._transforms.get(batch._params[paramOffset]._uint);
|
||||
_transform._invalidModel = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) {
|
||||
_transform._view = batch._transforms.get(batch._params[paramOffset]._uint);
|
||||
_transform._invalidView = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) {
|
||||
memcpy(&_transform._projection, batch.editData(batch._params[paramOffset]._uint), sizeof(Mat4));
|
||||
_transform._invalidProj = true;
|
||||
}
|
||||
|
||||
void GLBackend::initTransform() {
|
||||
#if defined(Q_OS_WIN)
|
||||
glGenBuffers(1, &_transform._transformObjectBuffer);
|
||||
glGenBuffers(1, &_transform._transformCameraBuffer);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformObjectBuffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformCameraBuffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW);
|
||||
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::killTransform() {
|
||||
#if defined(Q_OS_WIN)
|
||||
glDeleteBuffers(1, &_transform._transformObjectBuffer);
|
||||
glDeleteBuffers(1, &_transform._transformCameraBuffer);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
void GLBackend::updateTransform() {
|
||||
// Check all the dirty flags and update the state accordingly
|
||||
if (_transform._invalidProj) {
|
||||
_transform._transformCamera._projection = _transform._projection;
|
||||
}
|
||||
|
||||
if (_transform._invalidView) {
|
||||
_transform._view.getInverseMatrix(_transform._transformCamera._view);
|
||||
_transform._view.getMatrix(_transform._transformCamera._viewInverse);
|
||||
}
|
||||
|
||||
if (_transform._invalidModel) {
|
||||
_transform._model.getMatrix(_transform._transformObject._model);
|
||||
_transform._model.getInverseMatrix(_transform._transformObject._modelInverse);
|
||||
}
|
||||
|
||||
if (_transform._invalidView || _transform._invalidProj) {
|
||||
Mat4 viewUntranslated = _transform._transformCamera._view;
|
||||
viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
_transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated;
|
||||
}
|
||||
|
||||
if (_transform._invalidView || _transform._invalidProj) {
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_transform._invalidModel) {
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformObjectBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._transformObjectBuffer);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _transform._transformCameraBuffer);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
|
||||
// Do it again for fixed pipeline until we can get rid of it
|
||||
if (_transform._invalidProj) {
|
||||
if (_transform._lastMode != GL_PROJECTION) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
_transform._lastMode = GL_PROJECTION;
|
||||
}
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&_transform._projection));
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
if (_transform._invalidModel || _transform._invalidView) {
|
||||
if (!_transform._model.isIdentity()) {
|
||||
if (_transform._lastMode != GL_MODELVIEW) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
_transform._lastMode = GL_MODELVIEW;
|
||||
}
|
||||
Transform::Mat4 modelView;
|
||||
if (!_transform._view.isIdentity()) {
|
||||
Transform mvx;
|
||||
Transform::inverseMult(mvx, _transform._view, _transform._model);
|
||||
mvx.getMatrix(modelView);
|
||||
} else {
|
||||
_transform._model.getMatrix(modelView);
|
||||
}
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
|
||||
} else {
|
||||
if (!_transform._view.isIdentity()) {
|
||||
if (_transform._lastMode != GL_MODELVIEW) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
_transform._lastMode = GL_MODELVIEW;
|
||||
}
|
||||
Transform::Mat4 modelView;
|
||||
_transform._view.getInverseMatrix(modelView);
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
|
||||
} else {
|
||||
// TODO: eventually do something about the matrix when neither view nor model is specified?
|
||||
// glLoadIdentity();
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Flags are clean
|
||||
_transform._invalidView = _transform._invalidProj = _transform._invalidModel = false;
|
||||
}
|
||||
|
||||
|
34
libraries/gpu/src/gpu/Pipeline.cpp
Executable file
34
libraries/gpu/src/gpu/Pipeline.cpp
Executable file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Pipeline.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/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 "Pipeline.h"
|
||||
#include <math.h>
|
||||
#include <QDebug>
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
Pipeline::Pipeline():
|
||||
_program(),
|
||||
_states()
|
||||
{
|
||||
}
|
||||
|
||||
Pipeline::~Pipeline()
|
||||
{
|
||||
}
|
||||
|
||||
Pipeline* Pipeline::create(const ShaderPointer& program, const States& states) {
|
||||
Pipeline* pipeline = new Pipeline();
|
||||
pipeline->_program = program;
|
||||
pipeline->_states = states;
|
||||
|
||||
return pipeline;
|
||||
}
|
53
libraries/gpu/src/gpu/Pipeline.h
Executable file
53
libraries/gpu/src/gpu/Pipeline.h
Executable file
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// Pipeline.h
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/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_Pipeline_h
|
||||
#define hifi_gpu_Pipeline_h
|
||||
|
||||
#include "Resource.h"
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include "Shader.h"
|
||||
#include "State.h"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class Pipeline {
|
||||
public:
|
||||
static Pipeline* create(const ShaderPointer& program, const States& states);
|
||||
~Pipeline();
|
||||
|
||||
const ShaderPointer& getProgram() const { return _program; }
|
||||
|
||||
const States& getStates() const { return _states; }
|
||||
|
||||
protected:
|
||||
ShaderPointer _program;
|
||||
States _states;
|
||||
|
||||
Pipeline();
|
||||
Pipeline(const Pipeline& pipeline); // deep copy of the sysmem shader
|
||||
Pipeline& operator=(const Pipeline& pipeline); // deep copy of the sysmem texture
|
||||
|
||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
friend class Backend;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr< Pipeline > PipelinePointer;
|
||||
typedef std::vector< PipelinePointer > Pipelines;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -38,6 +38,18 @@ public:
|
|||
// The size in bytes of data stored in the resource
|
||||
virtual Size getSize() const = 0;
|
||||
|
||||
enum Type {
|
||||
BUFFER = 0,
|
||||
TEXTURE_1D,
|
||||
TEXTURE_2D,
|
||||
TEXTURE_3D,
|
||||
TEXTURE_CUBE,
|
||||
TEXTURE_1D_ARRAY,
|
||||
TEXTURE_2D_ARRAY,
|
||||
TEXTURE_3D_ARRAY,
|
||||
TEXTURE_CUBE_ARRAY,
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
Resource() {}
|
||||
|
@ -140,12 +152,11 @@ protected:
|
|||
|
||||
Sysmem* _sysmem = NULL;
|
||||
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
|
||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
|
||||
friend class Backend;
|
||||
};
|
||||
|
||||
|
|
73
libraries/gpu/src/gpu/Shader.cpp
Executable file
73
libraries/gpu/src/gpu/Shader.cpp
Executable file
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// Shader.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 2/27/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 "Shader.h"
|
||||
#include <math.h>
|
||||
#include <QDebug>
|
||||
|
||||
#include "Context.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
Shader::Shader(Type type, const Source& source):
|
||||
_source(source),
|
||||
_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
Shader::Shader(Type type, Pointer& vertex, Pointer& pixel):
|
||||
_type(type)
|
||||
{
|
||||
_shaders.resize(2);
|
||||
_shaders[VERTEX] = vertex;
|
||||
_shaders[PIXEL] = pixel;
|
||||
}
|
||||
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
}
|
||||
|
||||
Shader* Shader::createVertex(const Source& source) {
|
||||
Shader* shader = new Shader(VERTEX, source);
|
||||
return shader;
|
||||
}
|
||||
|
||||
Shader* Shader::createPixel(const Source& source) {
|
||||
Shader* shader = new Shader(PIXEL, source);
|
||||
return shader;
|
||||
}
|
||||
|
||||
Shader* Shader::createProgram(Pointer& vertexShader, Pointer& pixelShader) {
|
||||
if (vertexShader && vertexShader->getType() == VERTEX) {
|
||||
if (pixelShader && pixelShader->getType() == PIXEL) {
|
||||
Shader* shader = new Shader(PROGRAM, vertexShader, pixelShader);
|
||||
return shader;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) {
|
||||
_uniforms = uniforms;
|
||||
_buffers = buffers;
|
||||
_textures = textures;
|
||||
_samplers = samplers;
|
||||
_inputs = inputs;
|
||||
_outputs = outputs;
|
||||
}
|
||||
|
||||
bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
|
||||
if (shader.isProgram()) {
|
||||
return Context::makeProgram(shader, bindings);
|
||||
}
|
||||
return false;
|
||||
}
|
165
libraries/gpu/src/gpu/Shader.h
Executable file
165
libraries/gpu/src/gpu/Shader.h
Executable file
|
@ -0,0 +1,165 @@
|
|||
//
|
||||
// Shader.h
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 2/27/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_Shader_h
|
||||
#define hifi_gpu_Shader_h
|
||||
|
||||
#include "Resource.h"
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class Shader {
|
||||
public:
|
||||
|
||||
typedef QSharedPointer< Shader > Pointer;
|
||||
typedef std::vector< Pointer > Shaders;
|
||||
|
||||
class Source {
|
||||
public:
|
||||
enum Language {
|
||||
GLSL = 0,
|
||||
};
|
||||
|
||||
Source() {}
|
||||
Source(const std::string& code, Language lang = GLSL) : _code(code), _lang(lang) {}
|
||||
Source(const Source& source) : _code(source._code), _lang(source._lang) {}
|
||||
virtual ~Source() {}
|
||||
|
||||
virtual const std::string& getCode() const { return _code; }
|
||||
|
||||
protected:
|
||||
std::string _code;
|
||||
Language _lang = GLSL;
|
||||
};
|
||||
|
||||
class Slot {
|
||||
public:
|
||||
|
||||
std::string _name;
|
||||
uint32 _location;
|
||||
Element _element;
|
||||
uint16 _resourceType;
|
||||
|
||||
Slot(const std::string& name, uint16 location, const Element& element, uint16 resourceType = Resource::BUFFER) :
|
||||
_name(name), _location(location), _element(element), _resourceType(resourceType) {}
|
||||
|
||||
};
|
||||
|
||||
class Binding {
|
||||
public:
|
||||
std::string _name;
|
||||
uint32 _location;
|
||||
Binding(const std::string&& name, uint32 loc = 0) : _name(name), _location(loc) {}
|
||||
};
|
||||
|
||||
template <typename T> class Less {
|
||||
public:
|
||||
bool operator() (const T& x, const T& y) const { return x._name < y._name; }
|
||||
};
|
||||
typedef std::set<Slot, Less<Slot>> SlotSet;
|
||||
typedef std::set<Binding, Less<Binding>> BindingSet;
|
||||
|
||||
|
||||
enum Type {
|
||||
VERTEX = 0,
|
||||
PIXEL,
|
||||
GEOMETRY,
|
||||
NUM_DOMAINS,
|
||||
|
||||
PROGRAM,
|
||||
};
|
||||
|
||||
static Shader* createVertex(const Source& source);
|
||||
static Shader* createPixel(const Source& source);
|
||||
|
||||
static Shader* createProgram(Pointer& vertexShader, Pointer& pixelShader);
|
||||
|
||||
|
||||
~Shader();
|
||||
|
||||
Type getType() const { return _type; }
|
||||
bool isProgram() const { return getType() > NUM_DOMAINS; }
|
||||
bool isDomain() const { return getType() < NUM_DOMAINS; }
|
||||
|
||||
const Source& getSource() const { return _source; }
|
||||
|
||||
const Shaders& getShaders() const { return _shaders; }
|
||||
|
||||
// Access the exposed uniform, input and output slot
|
||||
const SlotSet& getUniforms() const { return _uniforms; }
|
||||
const SlotSet& getBuffers() const { return _buffers; }
|
||||
const SlotSet& getTextures() const { return _textures; }
|
||||
const SlotSet& getSamplers() const { return _samplers; }
|
||||
|
||||
const SlotSet& getInputs() const { return _inputs; }
|
||||
const SlotSet& getOutputs() const { return _outputs; }
|
||||
|
||||
// Define the list of uniforms, inputs and outputs for the shader
|
||||
// This call is intendend to build the list of exposed slots in order
|
||||
// to correctly bind resource to the shader.
|
||||
// These can be build "manually" from knowledge of the atual shader code
|
||||
// or automatically by calling "makeShader()", this is the preferred way
|
||||
void defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs);
|
||||
|
||||
// makeProgram(...) make a program shader ready to be used in a Batch.
|
||||
// It compiles the sub shaders, link them and defines the Slots and their bindings.
|
||||
// If the shader passed is not a program, nothing happens.
|
||||
//
|
||||
// It is possible to provide a set of slot bindings (from the name of the slot to a unit number) allowing
|
||||
// to make sure slots with the same semantics can be always bound on the same location from shader to shader.
|
||||
// For example, the "diffuseMap" can always be bound to texture unit #1 for different shaders by specifying a Binding("diffuseMap", 1)
|
||||
//
|
||||
// As of now (03/2015), the call to makeProgram is in fact calling gpu::Context::makeProgram and does rely
|
||||
// on the underneath gpu::Context::Backend available. Since we only support glsl, this means that it relies
|
||||
// on a glContext and the driver to compile the glsl shader.
|
||||
// Hoppefully in a few years the shader compilation will be completely abstracted in a separate shader compiler library
|
||||
// independant of the graphics api in use underneath (looking at you opengl & vulkan).
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
|
||||
|
||||
protected:
|
||||
Shader(Type type, const Source& source);
|
||||
Shader(Type type, Pointer& vertex, Pointer& pixel);
|
||||
|
||||
Shader(const Shader& shader); // deep copy of the sysmem shader
|
||||
Shader& operator=(const Shader& shader); // deep copy of the sysmem texture
|
||||
|
||||
// Source contains the actual source code or nothing if the shader is a program
|
||||
Source _source;
|
||||
|
||||
// if shader is composed of sub shaders, here they are
|
||||
Shaders _shaders;
|
||||
|
||||
// List of exposed uniform, input and output slots
|
||||
SlotSet _uniforms;
|
||||
SlotSet _buffers;
|
||||
SlotSet _textures;
|
||||
SlotSet _samplers;
|
||||
SlotSet _inputs;
|
||||
SlotSet _outputs;
|
||||
|
||||
// The type of the shader, the master key
|
||||
Type _type;
|
||||
|
||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
friend class Backend;
|
||||
};
|
||||
|
||||
typedef Shader::Pointer ShaderPointer;
|
||||
typedef std::vector< ShaderPointer > Shaders;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
20
libraries/gpu/src/gpu/State.cpp
Executable file
20
libraries/gpu/src/gpu/State.cpp
Executable file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// State.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/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 "State.h"
|
||||
#include <QDebug>
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
|
||||
State::~State()
|
||||
{
|
||||
}
|
88
libraries/gpu/src/gpu/State.h
Executable file
88
libraries/gpu/src/gpu/State.h
Executable file
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// Pipeline.h
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/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_State_h
|
||||
#define hifi_gpu_State_h
|
||||
|
||||
#include "Format.h"
|
||||
#include <vector>
|
||||
#include <QSharedPointer>
|
||||
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class GPUObject;
|
||||
|
||||
class State {
|
||||
public:
|
||||
State() {}
|
||||
virtual ~State();
|
||||
|
||||
// Work in progress, not used
|
||||
/*
|
||||
enum Field {
|
||||
FILL_MODE,
|
||||
CULL_MODE,
|
||||
DEPTH_BIAS,
|
||||
DEPTH_BIAS_CLAMP,
|
||||
DEPTH_BIASSLOPE_SCALE,
|
||||
|
||||
FRONT_CLOCKWISE,
|
||||
DEPTH_CLIP_ENABLE,
|
||||
SCISSR_ENABLE,
|
||||
MULTISAMPLE_ENABLE,
|
||||
ANTIALISED_LINE_ENABLE,
|
||||
|
||||
DEPTH_ENABLE,
|
||||
DEPTH_WRITE_MASK,
|
||||
DEPTH_FUNCTION,
|
||||
|
||||
STENCIL_ENABLE,
|
||||
STENCIL_READ_MASK,
|
||||
STENCIL_WRITE_MASK,
|
||||
STENCIL_FUNCTION_FRONT,
|
||||
STENCIL_FUNCTION_BACK,
|
||||
STENCIL_REFERENCE,
|
||||
|
||||
BLEND_INDEPENDANT_ENABLE,
|
||||
BLEND_ENABLE,
|
||||
BLEND_SOURCE,
|
||||
BLEND_DESTINATION,
|
||||
BLEND_OPERATION,
|
||||
BLEND_SOURCE_ALPHA,
|
||||
BLEND_DESTINATION_ALPHA,
|
||||
BLEND_OPERATION_ALPHA,
|
||||
BLEND_WRITE_MASK,
|
||||
BLEND_FACTOR,
|
||||
|
||||
SAMPLE_MASK,
|
||||
|
||||
ALPHA_TO_COVERAGE_ENABLE,
|
||||
};
|
||||
*/
|
||||
|
||||
protected:
|
||||
State(const State& state);
|
||||
State& operator=(const State& state);
|
||||
|
||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
friend class Backend;
|
||||
};
|
||||
|
||||
typedef QSharedPointer< State > StatePointer;
|
||||
typedef std::vector< StatePointer > States;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -207,12 +207,10 @@ protected:
|
|||
|
||||
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.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
|
||||
friend class Backend;
|
||||
};
|
||||
|
||||
|
|
245
libraries/model/src/model/Atmosphere.slh
Executable file
245
libraries/model/src/model/Atmosphere.slh
Executable file
|
@ -0,0 +1,245 @@
|
|||
<!
|
||||
// Atmospheric.slh
|
||||
//
|
||||
// Created by Sam Gateau on 3/9/15.
|
||||
// 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
|
||||
!>
|
||||
<@if not MODEL_ATMOSPHERE_SLH@>
|
||||
<@def MODEL_ATMOSPHERE_SLH@>
|
||||
|
||||
<!
|
||||
// Code is a modified version of:
|
||||
// http://http.developer.nvidia.com/GPUGems/gpugems_app01.html
|
||||
// Atmospheric scattering fragment shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
!>
|
||||
|
||||
struct Atmosphere {
|
||||
vec4 _invWaveLength;
|
||||
vec4 _radiuses;
|
||||
vec4 _scales;
|
||||
vec4 _scatterings;
|
||||
vec4 _control;
|
||||
};
|
||||
|
||||
const int numSamples = 2;
|
||||
|
||||
vec3 getAtmosphereInvWaveLength(Atmosphere a) { return a._invWaveLength.xyz; } // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
|
||||
float getAtmosphereInnerRadius(Atmosphere a) { return a._radiuses.x; } // The inner (planetary) radius
|
||||
float getAtmosphereOuterRadius(Atmosphere a) { return a._radiuses.y; } // The outer (atmosphere) radius
|
||||
|
||||
float getAtmosphereScale(Atmosphere a) { return a._scales.x; } // 1 / (outerRadius - innerRadius)
|
||||
float getAtmosphereScaleDepth(Atmosphere a) { return a._scales.y; } // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
float getAtmosphereScaleOverScaleDepth(Atmosphere a) { return a._scales.z; } // scale / scaleDepth
|
||||
|
||||
vec4 getAtmosphereScattering(Atmosphere a) { return a._scatterings; } // The full Mie and Rayleigh scattering coefficients
|
||||
float getAtmosphereKrESun(Atmosphere a) { return a._scatterings.x; } // Kr * ESun
|
||||
float getAtmosphereKmESun(Atmosphere a) { return a._scatterings.y; } // Km * ESun
|
||||
float getAtmosphereKr4PI(Atmosphere a) { return a._scatterings.z; } // Kr * 4 * PI
|
||||
float getAtmosphereKm4PI(Atmosphere a) { return a._scatterings.w; } // Km * 4 * PI
|
||||
|
||||
float getAtmosphereNumSamples(Atmosphere a) { return a._control.x; } // numSamples
|
||||
vec2 getAtmosphereGAndG2(Atmosphere a) { return a._control.yz; } // g and g2
|
||||
|
||||
float atmosphereScale(float scaleDepth, float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return scaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
vec4 evalAtmosphereContribution(Atmosphere atmospheric, vec3 position, vec3 cameraPos, vec3 lightPos) {
|
||||
float fInnerRadius = getAtmosphereInnerRadius(atmospheric);
|
||||
float fSamples = getAtmosphereNumSamples(atmospheric);
|
||||
|
||||
vec3 v3InvWavelength = getAtmosphereInvWaveLength(atmospheric);
|
||||
vec4 scatteringCoefs = getAtmosphereScattering(atmospheric);
|
||||
float fKrESun = scatteringCoefs.x;
|
||||
float fKmESun = scatteringCoefs.y;
|
||||
float fKr4PI = scatteringCoefs.z;
|
||||
float fKm4PI = scatteringCoefs.w;
|
||||
|
||||
vec2 gAndg2 = getAtmosphereGAndG2(atmospheric);
|
||||
float g = gAndg2.x;
|
||||
float g2 = gAndg2.y;
|
||||
|
||||
float fScale = getAtmosphereScale(atmospheric);
|
||||
float fScaleDepth = getAtmosphereScaleDepth(atmospheric);
|
||||
float fScaleOverScaleDepth = getAtmosphereScaleOverScaleDepth(atmospheric);
|
||||
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = position;
|
||||
vec3 v3Ray = v3Pos - cameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = cameraPos;
|
||||
float fHeight = length(v3Start);
|
||||
float fDepthStart = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fHeight;
|
||||
float fStartOffset = fDepthStart * atmosphereScale(fScaleDepth, fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
// int nSamples = numSamples;
|
||||
int nSamples = int(fSamples);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(lightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99;
|
||||
float fScatter = (fStartOffset + fDepth * (atmosphereScale(fScaleDepth, fLightAngle) - atmosphereScale(fScaleDepth, fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
|
||||
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
|
||||
vec3 secondaryFrontColor = v3FrontColor * fKmESun;
|
||||
vec3 frontColor = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 v3Direction = cameraPos - v3Pos;
|
||||
|
||||
float fCos = dot(lightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
vec4 finalColor;
|
||||
|
||||
finalColor.rgb = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb;
|
||||
finalColor.a = finalColor.b;
|
||||
finalColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2));
|
||||
|
||||
return finalColor;
|
||||
}
|
||||
|
||||
|
||||
<@if GLPROFILE == PC_GL@>
|
||||
uniform atmosphereBuffer {
|
||||
Atmosphere _atmosphere;
|
||||
};
|
||||
Atmosphere getAtmosphere() {
|
||||
return _atmosphere;
|
||||
}
|
||||
<@else@>
|
||||
uniform vec4 atmosphereBuffer[9];
|
||||
Atmosphere getAtmosphere() {
|
||||
Atmosphere atmosphere;
|
||||
atmosphere._invWaveLength = atmosphereBuffer[0];
|
||||
atmosphere._radiuses = atmosphereBuffer[1];
|
||||
atmosphere._scales = atmosphereBuffer[2];
|
||||
atmosphere._scatterings = atmosphereBuffer[3];
|
||||
atmosphere._control = atmosphereBuffer[4];
|
||||
|
||||
return atmosphere;
|
||||
}
|
||||
<@endif@>
|
||||
|
||||
<!
|
||||
/*
|
||||
// uniform vec3 v3CameraPos; // The camera's current position
|
||||
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
uniform vec3 v3LightPos;
|
||||
uniform float g;
|
||||
uniform float g2;
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main (void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = position;
|
||||
vec3 v3Ray = v3Pos - v3CameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = v3CameraPos;
|
||||
float fHeight = length(v3Start);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fHeight;
|
||||
float fStartOffset = fDepth * scale(fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99;
|
||||
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
|
||||
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
|
||||
vec3 secondaryFrontColor = v3FrontColor * fKmESun;
|
||||
vec3 frontColor = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 v3Direction = v3CameraPos - v3Pos;
|
||||
|
||||
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
gl_FragColor.rgb = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0/2.2));
|
||||
}
|
||||
*/
|
||||
!>
|
||||
|
||||
<@endif@>
|
108
libraries/model/src/model/SkyFromAtmosphere.slf
Executable file
108
libraries/model/src/model/SkyFromAtmosphere.slf
Executable file
|
@ -0,0 +1,108 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering fragment shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
uniform vec3 v3LightPos;
|
||||
uniform float g;
|
||||
uniform float g2;
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main (void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = position;
|
||||
vec3 v3Ray = v3Pos - v3CameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = v3CameraPos;
|
||||
float fHeight = length(v3Start);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fHeight;
|
||||
float fStartOffset = fDepth * scale(fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99;
|
||||
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
|
||||
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
|
||||
vec3 secondaryFrontColor = v3FrontColor * fKmESun;
|
||||
vec3 frontColor = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 v3Direction = v3CameraPos - v3Pos;
|
||||
|
||||
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
gl_FragColor.rgb = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0/2.2));
|
||||
}
|
68
libraries/model/src/model/SkyFromAtmosphere.slv
Executable file
68
libraries/model/src/model/SkyFromAtmosphere.slv
Executable file
|
@ -0,0 +1,68 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering vertex shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3LightPos; // The direction vector to the light source
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fOuterRadius; // The outer (atmosphere) radius
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
position = gl_Vertex.xyz * fOuterRadius;
|
||||
|
||||
gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0);
|
||||
}
|
114
libraries/model/src/model/SkyFromSpace.slf
Executable file
114
libraries/model/src/model/SkyFromSpace.slf
Executable file
|
@ -0,0 +1,114 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering fragment shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3LightPos; // The direction vector to the light source
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fCameraHeight2; // fCameraHeight^2
|
||||
uniform float fOuterRadius; // The outer (atmosphere) radius
|
||||
uniform float fOuterRadius2; // fOuterRadius^2
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
uniform float g;
|
||||
uniform float g2;
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
|
||||
void main (void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = position;
|
||||
vec3 v3Ray = v3Pos - v3CameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)
|
||||
float B = 2.0 * dot(v3CameraPos, v3Ray);
|
||||
float C = fCameraHeight2 - fOuterRadius2;
|
||||
float fDet = max(0.0, B*B - 4.0 * C);
|
||||
float fNear = 0.5 * (-B - sqrt(fDet));
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = v3CameraPos + v3Ray * fNear;
|
||||
fFar -= fNear;
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;
|
||||
float fStartDepth = exp(-1.0 / fScaleDepth);
|
||||
float fStartOffset = fStartDepth * scale(fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99;
|
||||
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
vec3 v3Direction = v3CameraPos - v3Pos;
|
||||
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
vec3 color = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 secondaryColor = v3FrontColor * fKmESun;
|
||||
gl_FragColor.rgb = color + fMiePhase * secondaryColor;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0/2.2));
|
||||
}
|
43
libraries/model/src/model/SkyFromSpace.slv
Executable file
43
libraries/model/src/model/SkyFromSpace.slv
Executable file
|
@ -0,0 +1,43 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering vertex shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform float fOuterRadius; // The outer (atmosphere) radius
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
position = gl_Vertex.xyz * fOuterRadius;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0);
|
||||
}
|
|
@ -13,6 +13,9 @@
|
|||
#include <glm/gtx/transform.hpp>
|
||||
#include <math.h>
|
||||
|
||||
#include "SkyFromAtmosphere_vert.h"
|
||||
#include "SkyFromAtmosphere_frag.h"
|
||||
|
||||
using namespace model;
|
||||
|
||||
|
||||
|
@ -131,6 +134,56 @@ void EarthSunModel::setSunLongitude(float lon) {
|
|||
_sunLongitude = validateLongitude(lon);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
Atmosphere::Atmosphere() {
|
||||
// only if created from nothing shall we create the Buffer to store the properties
|
||||
Data data;
|
||||
_dataBuffer = gpu::BufferView(new gpu::Buffer(sizeof(Data), (const gpu::Buffer::Byte*) &data));
|
||||
|
||||
setScatteringWavelength(_scatteringWavelength);
|
||||
setRayleighScattering(_rayleighScattering);
|
||||
setInnerOuterRadiuses(getInnerRadius(), getOuterRadius());
|
||||
}
|
||||
|
||||
void Atmosphere::setScatteringWavelength(Vec3 wavelength) {
|
||||
_scatteringWavelength = wavelength;
|
||||
Data& data = editData();
|
||||
data._invWaveLength = Vec4(1.0f / powf(wavelength.x, 4.0f), 1.0f / powf(wavelength.y, 4.0f), 1.0f / powf(wavelength.z, 4.0f), 0.0f);
|
||||
}
|
||||
|
||||
void Atmosphere::setRayleighScattering(float scattering) {
|
||||
_rayleighScattering = scattering;
|
||||
updateScattering();
|
||||
}
|
||||
|
||||
void Atmosphere::setMieScattering(float scattering) {
|
||||
_mieScattering = scattering;
|
||||
updateScattering();
|
||||
}
|
||||
|
||||
void Atmosphere::setSunBrightness(float brightness) {
|
||||
_sunBrightness = brightness;
|
||||
updateScattering();
|
||||
}
|
||||
|
||||
void Atmosphere::updateScattering() {
|
||||
Data& data = editData();
|
||||
|
||||
data._scatterings.x = getRayleighScattering() * getSunBrightness();
|
||||
data._scatterings.y = getMieScattering() * getSunBrightness();
|
||||
|
||||
data._scatterings.z = getRayleighScattering() * 4.0f * glm::pi<float>();
|
||||
data._scatterings.w = getMieScattering() * 4.0f * glm::pi<float>();
|
||||
}
|
||||
|
||||
void Atmosphere::setInnerOuterRadiuses(float inner, float outer) {
|
||||
Data& data = editData();
|
||||
data._radiuses.x = inner;
|
||||
data._radiuses.y = outer;
|
||||
data._scales.x = 1.0f / (outer - inner);
|
||||
data._scales.z = data._scales.x / data._scales.y;
|
||||
}
|
||||
|
||||
|
||||
const int NUM_DAYS_PER_YEAR = 365;
|
||||
const float NUM_HOURS_PER_DAY = 24.0f;
|
||||
|
@ -150,6 +203,12 @@ SunSkyStage::SunSkyStage() :
|
|||
setDayTime(12.0f);
|
||||
// Begining of march
|
||||
setYearTime(60.0f);
|
||||
|
||||
auto skyFromAtmosphereVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(SkyFromAtmosphere_vert)));
|
||||
auto skyFromAtmosphereFragment = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(SkyFromAtmosphere_frag)));
|
||||
auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyFromAtmosphereVertex, skyFromAtmosphereFragment));
|
||||
_skyPipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, gpu::States()));
|
||||
|
||||
}
|
||||
|
||||
SunSkyStage::~SunSkyStage() {
|
||||
|
@ -205,5 +264,12 @@ void SunSkyStage::updateGraphicsObject() const {
|
|||
double originAlt = _earthSunModel.getAltitude();
|
||||
_sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f));
|
||||
|
||||
static int firstTime = 0;
|
||||
if (firstTime == 0) {
|
||||
firstTime++;
|
||||
bool result = gpu::Shader::makeProgram(*(_skyPipeline->getProgram()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#ifndef hifi_model_Stage_h
|
||||
#define hifi_model_Stage_h
|
||||
|
||||
#include "gpu/Pipeline.h"
|
||||
|
||||
#include "Light.h"
|
||||
|
||||
namespace model {
|
||||
|
@ -104,6 +106,60 @@ protected:
|
|||
static Mat4d evalWorldToGeoLocationMat(double longitude, double latitude, double altitude, double scale);
|
||||
};
|
||||
|
||||
|
||||
class Atmosphere {
|
||||
public:
|
||||
|
||||
Atmosphere();
|
||||
Atmosphere(const Atmosphere& atmosphere);
|
||||
Atmosphere& operator= (const Atmosphere& atmosphere);
|
||||
virtual ~Atmosphere() {};
|
||||
|
||||
|
||||
void setScatteringWavelength(Vec3 wavelength);
|
||||
const Vec3& getScatteringWavelength() const { return _scatteringWavelength; }
|
||||
|
||||
void setRayleighScattering(float scattering);
|
||||
float getRayleighScattering() const { return _rayleighScattering; }
|
||||
|
||||
void setMieScattering(float scattering);
|
||||
float getMieScattering() const { return _mieScattering; }
|
||||
|
||||
void setSunBrightness(float brightness);
|
||||
float getSunBrightness() const { return _sunBrightness; }
|
||||
|
||||
void setInnerOuterRadiuses(float inner, float outer);
|
||||
float getInnerRadius() const { return getData()._radiuses.x; }
|
||||
float getOuterRadius() const { return getData()._radiuses.y; }
|
||||
|
||||
// Data to access the attribute values of the atmosphere
|
||||
class Data {
|
||||
public:
|
||||
Vec4 _invWaveLength = Vec4(0.0f);
|
||||
Vec4 _radiuses = Vec4(6000.0f, 6025.0f, 0.0f, 0.0f);
|
||||
Vec4 _scales = Vec4(0.0f, 0.25f, 0.0f, 0.0f);
|
||||
Vec4 _scatterings = Vec4(0.0f);
|
||||
Vec4 _control = Vec4(2.0f, -0.990f, -0.990f*-0.990f, 0.f);
|
||||
|
||||
Data() {}
|
||||
};
|
||||
|
||||
const UniformBufferView& getDataBuffer() const { return _dataBuffer; }
|
||||
|
||||
protected:
|
||||
UniformBufferView _dataBuffer;
|
||||
Vec3 _scatteringWavelength = Vec3(0.650f, 0.570f, 0.475f);
|
||||
float _rayleighScattering = 0.0025f;
|
||||
float _mieScattering = 0.0010f;
|
||||
float _sunBrightness = 20.0f;
|
||||
|
||||
const Data& getData() const { return _dataBuffer.get<Data>(); }
|
||||
Data& editData() { return _dataBuffer.edit<Data>(); }
|
||||
|
||||
void updateScattering();
|
||||
};
|
||||
typedef QSharedPointer< Atmosphere > AtmospherePointer;
|
||||
|
||||
// Sun sky stage generates the rendering primitives to display a scene realistically
|
||||
// at the specified location and time around earth
|
||||
class SunSkyStage {
|
||||
|
@ -139,9 +195,13 @@ public:
|
|||
float getSunIntensity() const { return getSunLight()->getIntensity(); }
|
||||
|
||||
LightPointer getSunLight() const { valid(); return _sunLight; }
|
||||
AtmospherePointer getAtmosphere() const { valid(); return _atmosphere; }
|
||||
|
||||
protected:
|
||||
LightPointer _sunLight;
|
||||
AtmospherePointer _atmosphere;
|
||||
|
||||
gpu::PipelinePointer _skyPipeline;
|
||||
|
||||
float _dayTime;
|
||||
int _yearTime;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
<@include DeferredLighting.slh@>
|
||||
|
||||
|
||||
struct SphericalHarmonics {
|
||||
vec4 L00;
|
||||
vec4 L1m1;
|
||||
|
|
|
@ -270,6 +270,12 @@ void DeferredLightingEffect::render() {
|
|||
batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer());
|
||||
gpu::GLBackend::renderBatch(batch);
|
||||
}
|
||||
|
||||
if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) {
|
||||
gpu::Batch batch;
|
||||
batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer());
|
||||
gpu::GLBackend::renderBatch(batch);
|
||||
}
|
||||
glUniformMatrix4fv(locations->invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat));
|
||||
}
|
||||
|
||||
|
@ -511,6 +517,31 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit
|
|||
locations.lightBufferUnit = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
loc = program.uniformLocation("atmosphereBufferUnit");
|
||||
if (loc >= 0) {
|
||||
locations.atmosphereBufferUnit = loc;
|
||||
} else {
|
||||
locations.atmosphereBufferUnit = -1;
|
||||
}
|
||||
#elif defined(Q_OS_WIN)
|
||||
loc = glGetUniformBlockIndex(program.programId(), "atmosphereBufferUnit");
|
||||
if (loc >= 0) {
|
||||
glUniformBlockBinding(program.programId(), loc, 1);
|
||||
locations.atmosphereBufferUnit = 1;
|
||||
} else {
|
||||
locations.atmosphereBufferUnit = -1;
|
||||
}
|
||||
#else
|
||||
loc = program.uniformLocation("atmosphereBufferUnit");
|
||||
if (loc >= 0) {
|
||||
locations.atmosphereBufferUnit = loc;
|
||||
} else {
|
||||
locations.atmosphereBufferUnit = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
program.release();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "ProgramObject.h"
|
||||
|
||||
#include "model/Light.h"
|
||||
#include "model/Stage.h"
|
||||
|
||||
class AbstractViewStateInterface;
|
||||
class PostLightingRenderable;
|
||||
|
@ -73,6 +74,7 @@ public:
|
|||
// update global lighting
|
||||
void setAmbientLightMode(int preset);
|
||||
void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity);
|
||||
void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; }
|
||||
|
||||
private:
|
||||
DeferredLightingEffect() {}
|
||||
|
@ -89,6 +91,7 @@ private:
|
|||
int radius;
|
||||
int ambientSphere;
|
||||
int lightBufferUnit;
|
||||
int atmosphereBufferUnit;
|
||||
int invViewMat;
|
||||
};
|
||||
|
||||
|
@ -146,6 +149,7 @@ private:
|
|||
AbstractViewStateInterface* _viewState;
|
||||
|
||||
int _ambientLightMode = 0;
|
||||
model::AtmospherePointer _atmosphere;
|
||||
};
|
||||
|
||||
/// Simple interface for objects that require something to be rendered after deferred lighting.
|
||||
|
|
|
@ -299,73 +299,156 @@ void Model::initJointTransforms() {
|
|||
|
||||
void Model::init() {
|
||||
if (!_program.isLinked()) {
|
||||
/* //Work in progress not used yet
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), 1));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3));
|
||||
|
||||
// Vertex shaders
|
||||
auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert)));
|
||||
auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert)));
|
||||
auto modelLightmapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_vert)));
|
||||
auto modelLightmapNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)));
|
||||
auto modelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_shadow_vert)));
|
||||
auto skinModelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_vert)));
|
||||
auto skinModelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)));
|
||||
auto skinModelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_shadow_vert)));
|
||||
|
||||
// Pixel shaders
|
||||
auto modelPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag)));
|
||||
auto modelNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_map_frag)));
|
||||
auto modelSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_specular_map_frag)));
|
||||
auto modelNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)));
|
||||
auto modelTranslucentPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_translucent_frag)));
|
||||
auto modelShadowPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_shadow_frag)));
|
||||
auto modelLightmapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_frag)));
|
||||
auto modelLightmapNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)));
|
||||
auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)));
|
||||
auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)));
|
||||
|
||||
|
||||
bool makeResult = false;
|
||||
|
||||
// Programs
|
||||
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto normalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*normalMapProgram, slotBindings);
|
||||
|
||||
auto specularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*specularMapProgram, slotBindings);
|
||||
|
||||
auto normalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*normalSpecularMapProgram, slotBindings);
|
||||
|
||||
auto translucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelTranslucentPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*translucentProgram, slotBindings);
|
||||
|
||||
auto shadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelShadowVertex, modelShadowPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*shadowProgram, slotBindings);
|
||||
|
||||
auto lightmapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*lightmapProgram, slotBindings);
|
||||
|
||||
auto lightmapNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*lightmapNormalMapProgram, slotBindings);
|
||||
|
||||
auto lightmapSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*lightmapSpecularMapProgram, slotBindings);
|
||||
|
||||
auto lightmapNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*lightmapNormalSpecularMapProgram, slotBindings);
|
||||
|
||||
auto skinProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinProgram, slotBindings);
|
||||
|
||||
auto skinNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinNormalMapProgram, slotBindings);
|
||||
|
||||
auto skinSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinSpecularMapProgram, slotBindings);
|
||||
|
||||
auto skinNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinNormalSpecularMapProgram, slotBindings);
|
||||
|
||||
auto skinShadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelShadowVertex, modelShadowPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinShadowProgram, slotBindings);
|
||||
|
||||
auto skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinTranslucentProgram, slotBindings);
|
||||
*/
|
||||
|
||||
_program.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_program.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
||||
initProgram(_program, _locations);
|
||||
|
||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||
initProgram(_normalMapProgram, _normalMapLocations);
|
||||
|
||||
_specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
||||
initProgram(_specularMapProgram, _specularMapLocations);
|
||||
|
||||
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
||||
initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations);
|
||||
|
||||
_translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
||||
initProgram(_translucentProgram, _translucentLocations);
|
||||
|
||||
// Lightmap
|
||||
_lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
||||
_lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag);
|
||||
initProgram(_lightmapProgram, _lightmapLocations);
|
||||
|
||||
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
||||
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag);
|
||||
initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations);
|
||||
|
||||
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
||||
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag);
|
||||
initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations);
|
||||
|
||||
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
||||
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag);
|
||||
initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations);
|
||||
// end lightmap
|
||||
|
||||
|
||||
_shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert);
|
||||
_shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
||||
// Shadow program uses the same locations as standard rendering path but we still need to set the bindings
|
||||
Model::Locations tempLoc;
|
||||
initProgram(_shadowProgram, tempLoc);
|
||||
|
||||
_skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||
_skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
||||
initSkinProgram(_skinProgram, _skinLocations);
|
||||
|
||||
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
||||
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||
initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations);
|
||||
|
||||
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
||||
initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations);
|
||||
|
||||
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
||||
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
||||
initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations);
|
||||
|
||||
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert);
|
||||
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
||||
initSkinProgram(_skinShadowProgram, _skinShadowLocations);
|
||||
|
||||
|
||||
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||
|
||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||
initProgram(_normalMapProgram, _normalMapLocations);
|
||||
|
||||
_specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
||||
initProgram(_specularMapProgram, _specularMapLocations);
|
||||
|
||||
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
||||
initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations);
|
||||
|
||||
_translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
||||
initProgram(_translucentProgram, _translucentLocations);
|
||||
|
||||
// Lightmap
|
||||
_lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
||||
_lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag);
|
||||
initProgram(_lightmapProgram, _lightmapLocations);
|
||||
|
||||
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
||||
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag);
|
||||
initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations);
|
||||
|
||||
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
||||
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag);
|
||||
initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations);
|
||||
|
||||
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
||||
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag);
|
||||
initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations);
|
||||
// end lightmap
|
||||
|
||||
|
||||
_shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert);
|
||||
_shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
||||
// Shadow program uses the same locations as standard rendering path but we still need to set the bindings
|
||||
Model::Locations tempLoc;
|
||||
initProgram(_shadowProgram, tempLoc);
|
||||
|
||||
_skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||
_skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
||||
initSkinProgram(_skinProgram, _skinLocations);
|
||||
|
||||
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
||||
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||
initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations);
|
||||
|
||||
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
||||
initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations);
|
||||
|
||||
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
||||
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
||||
initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations);
|
||||
|
||||
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert);
|
||||
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
||||
initSkinProgram(_skinShadowProgram, _skinShadowLocations);
|
||||
|
||||
|
||||
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
||||
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
|
||||
}
|
||||
|
|
|
@ -309,6 +309,7 @@ private:
|
|||
int _blendNumber;
|
||||
int _appliedBlendNumber;
|
||||
|
||||
|
||||
static ProgramObject _program;
|
||||
static ProgramObject _normalMapProgram;
|
||||
static ProgramObject _specularMapProgram;
|
||||
|
|
|
@ -192,9 +192,17 @@ int main (int argc, char** argv) {
|
|||
targetStringStream << "#ifndef scribe_" << targetName << "_h" << std::endl;
|
||||
targetStringStream << "#define scribe_" << targetName << "_h" << std::endl << std::endl;
|
||||
|
||||
targetStringStream << "const char " << targetName << "[] = R\"XXXX(" << destStringStream.str() << ")XXXX\";";
|
||||
// targetStringStream << "const char " << targetName << "[] = R\"XXXX(" << destStringStream.str() << ")XXXX\";";
|
||||
std::istringstream destStringStreamAgain(destStringStream.str());
|
||||
targetStringStream << "const char " << targetName << "[] = \n";
|
||||
while (!destStringStreamAgain.eof()) {
|
||||
std::string lineToken;
|
||||
std::getline(destStringStreamAgain, lineToken);
|
||||
// targetStringStream << "\"" << lineToken << "\"\n";
|
||||
targetStringStream << "R\"X(" << lineToken << ")X\"\"\\n\"\n";
|
||||
}
|
||||
|
||||
targetStringStream << std::endl << std::endl;
|
||||
targetStringStream << ";\n" << std::endl << std::endl;
|
||||
targetStringStream << "#endif" << std::endl;
|
||||
} else {
|
||||
targetStringStream << destStringStream.str();
|
||||
|
|
Loading…
Reference in a new issue