diff --git a/cmake/modules/FindATL.cmake b/cmake/modules/FindATL.cmake index f95b0267eb..ecb9078d82 100644 --- a/cmake/modules/FindATL.cmake +++ b/cmake/modules/FindATL.cmake @@ -16,8 +16,11 @@ # if (WIN32) - find_library(ATL_LIBRARY_RELEASE atls PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") - find_library(ATL_LIBRARY_DEBUG atlsd PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") + set(ATL_SEARCH_DIRS "C:\\WinDDK") + find_path(ATL_INCLUDE_DIRS atlbase.h PATH_SUFFIXES "7600.16385.1/inc/atl71" HINTS ${ATL_SEARCH_DIRS}) + + find_library(ATL_LIBRARY_RELEASE atls PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS ${ATL_SEARCH_DIRS}) + find_library(ATL_LIBRARY_DEBUG atlsd PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS ${ATL_SEARCH_DIRS}) include(SelectLibraryConfigurations) select_library_configurations(ATL) @@ -26,4 +29,4 @@ endif () set(ATL_LIBRARIES "${ATL_LIBRARY}") include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(ATL DEFAULT_MSG ATL_LIBRARIES) \ No newline at end of file +find_package_handle_standard_args(ATL DEFAULT_MSG ATL_INCLUDE_DIRS ATL_LIBRARIES) \ No newline at end of file diff --git a/interface/resources/shaders/metavoxel_heightfield_base.vert b/interface/resources/shaders/metavoxel_heightfield_base.vert index f097426e13..5486f5fa67 100644 --- a/interface/resources/shaders/metavoxel_heightfield_base.vert +++ b/interface/resources/shaders/metavoxel_heightfield_base.vert @@ -26,11 +26,14 @@ varying vec4 normal; void main(void) { // transform and store the normal for interpolation vec2 heightCoord = gl_MultiTexCoord0.st; - float deltaX = texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r - - texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r; - float deltaZ = texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r - - texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r; - normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0)); + vec4 neighborHeights = vec4(texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r, + texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r, + texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r, + texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r); + vec4 neighborsZero = step(1.0 / 255.0, neighborHeights); + normal = normalize(gl_ModelViewMatrix * vec4( + (neighborHeights.x - neighborHeights.y) * neighborsZero.x * neighborsZero.y, heightScale, + (neighborHeights.z - neighborHeights.w) * neighborsZero.z * neighborsZero.w, 0.0)); // add the height to the position float height = texture2D(heightMap, heightCoord).r; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 11ab5769cb..d7b47a549d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -432,6 +432,8 @@ Menu::Menu() : QMenu* metavoxelOptionsMenu = developerMenu->addMenu("Metavoxels"); addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::DisplayHermiteData, 0, false, Application::getInstance()->getMetavoxels(), SLOT(refreshVoxelData())); + addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::RenderHeightfields, 0, true); + addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::RenderDualContourSurfaces, 0, true); addActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::NetworkSimulator, 0, this, SLOT(showMetavoxelNetworkSimulator())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 80f7f1e006..66755f0e5b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -446,8 +446,10 @@ namespace MenuOption { const QString Quit = "Quit"; const QString ReloadAllScripts = "Reload All Scripts"; const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes"; + const QString RenderDualContourSurfaces = "Render Dual Contour Surfaces"; const QString RenderFocusIndicator = "Show Eye Focus"; const QString RenderHeadCollisionShapes = "Show Head Collision Shapes"; + const QString RenderHeightfields = "Render Heightfields"; const QString RenderLookAtVectors = "Show Look-at Vectors"; const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes"; const QString RenderResolution = "Scale Resolution"; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 8166c3938c..2071ea8c3d 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -2772,40 +2772,39 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - _baseHeightfieldProgram.bind(); - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()); - data.guide(heightfieldRenderVisitor); - - _baseHeightfieldProgram.release(); - - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); + if (Menu::getInstance()->isOptionChecked(MenuOption::RenderHeightfields)) { + _baseHeightfieldProgram.bind(); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()); + data.guide(heightfieldRenderVisitor); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + _baseHeightfieldProgram.release(); + } - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - _baseVoxelProgram.bind(); - - BufferRenderVisitor voxelRenderVisitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute()); - data.guide(voxelRenderVisitor); - - _baseVoxelProgram.release(); + if (Menu::getInstance()->isOptionChecked(MenuOption::RenderDualContourSurfaces)) { + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + _baseVoxelProgram.bind(); + + BufferRenderVisitor voxelRenderVisitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute()); + data.guide(voxelRenderVisitor); + + _baseVoxelProgram.release(); + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + } glDisable(GL_ALPHA_TEST); glDisable(GL_CULL_FACE); glEnable(GL_BLEND); - + glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false); } diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index bc557bdb57..31f08d9eae 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -166,6 +166,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } // use data to update fake Faceshift blendshape coefficients + const float JAW_OPEN_SCALE = 0.015f; const float JAW_OPEN_RATE = 0.9f; const float JAW_CLOSE_RATE = 0.90f; @@ -177,10 +178,28 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); + // _mouth2 = "mmmm" shape + // _mouth3 = "funnel" shape + // _mouth4 = "smile" shape + const float FUNNEL_PERIOD = 0.985f; + const float FUNNEL_RANDOM_PERIOD = 0.01f; + const float MMMM_POWER = 0.25f; + const float MMMM_PERIOD = 0.91f; + const float MMMM_RANDOM_PERIOD = 0.15f; + const float SMILE_PERIOD = 0.925f; + const float SMILE_RANDOM_PERIOD = 0.05f; + + _mouth3 = glm::mix(_audioJawOpen, _mouth3, FUNNEL_PERIOD + randFloat() * FUNNEL_RANDOM_PERIOD); + _mouth2 = glm::mix(_audioJawOpen * MMMM_POWER, _mouth2, MMMM_PERIOD + randFloat() * MMMM_RANDOM_PERIOD); + _mouth4 = glm::mix(_audioJawOpen, _mouth4, SMILE_PERIOD + randFloat() * SMILE_RANDOM_PERIOD); + Application::getInstance()->getFaceshift()->updateFakeCoefficients(_leftEyeBlink, _rightEyeBlink, _browAudioLift, _audioJawOpen, + _mouth2, + _mouth3, + _mouth4, _blendshapeCoefficients); } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index bc4142eab0..57d74adaf0 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -129,6 +129,9 @@ private: float _longTermAverageLoudness; float _audioAttack; float _audioJawOpen; + float _mouth2; + float _mouth3; + float _mouth4; glm::vec3 _angularVelocity; bool _renderLookatVectors; glm::vec3 _saccade; diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 74e36a98d1..fb74f416a9 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -125,8 +125,14 @@ void Faceshift::reset() { } void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, - float jawOpen, QVector& coefficients) const { - coefficients.resize(max((int)coefficients.size(), _jawOpenIndex + 1)); + float jawOpen, float mouth2, float mouth3, float mouth4, QVector& coefficients) const { + const int MMMM_BLENDSHAPE = 34; + const int FUNNEL_BLENDSHAPE = 40; + const int SMILE_LEFT_BLENDSHAPE = 28; + const int SMILE_RIGHT_BLENDSHAPE = 29; + const int MAX_FAKE_BLENDSHAPE = 40; // Largest modified blendshape from above and below + + coefficients.resize(max((int)coefficients.size(), MAX_FAKE_BLENDSHAPE + 1)); qFill(coefficients.begin(), coefficients.end(), 0.0f); coefficients[_leftBlinkIndex] = leftBlink; coefficients[_rightBlinkIndex] = rightBlink; @@ -134,6 +140,9 @@ void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float coefficients[_browUpLeftIndex] = browUp; coefficients[_browUpRightIndex] = browUp; coefficients[_jawOpenIndex] = jawOpen; + coefficients[SMILE_LEFT_BLENDSHAPE] = coefficients[SMILE_RIGHT_BLENDSHAPE] = mouth4; + coefficients[MMMM_BLENDSHAPE] = mouth2; + coefficients[FUNNEL_BLENDSHAPE] = mouth3; } void Faceshift::setTCPEnabled(bool enabled) { diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index e7d87827eb..3b4092c099 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -61,8 +61,14 @@ public: void update(); void reset(); - void updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, - float jawOpen, QVector& coefficients) const; + void updateFakeCoefficients(float leftBlink, + float rightBlink, + float browUp, + float jawOpen, + float mouth2, + float mouth3, + float mouth4, + QVector& coefficients) const; signals: diff --git a/interface/src/gpu/Batch.cpp b/interface/src/gpu/Batch.cpp new file mode 100644 index 0000000000..8b36ef8b33 --- /dev/null +++ b/interface/src/gpu/Batch.cpp @@ -0,0 +1,753 @@ +// +// Batch.cpp +// interface/src/gpu +// +// Created by Sam Gateau on 10/14/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "Batch.h" + +#include + +#define ADD_COMMAND(call) _commands.push_back(COMMAND_##call); _commandCalls.push_back(&gpu::Batch::do_##call); _commandOffsets.push_back(_params.size()); + +//#define DO_IT_NOW(call, offset) runLastCommand(); +#define DO_IT_NOW(call, offset) + +#define CHECK_GL_ERROR() ::gpu::backend::checkGLError() + +using namespace gpu; + +Batch::Batch() : + _commands(), + _commandCalls(), + _commandOffsets(), + _params(), + _resources(), + _data(){ +} + +Batch::~Batch() { +} + +void Batch::clear() { + _commands.clear(); + _commandCalls.clear(); + _commandOffsets.clear(); + _params.clear(); + _resources.clear(); + _data.clear(); +} + +uint32 Batch::cacheResource(Resource* res) { + uint32 offset = _resources.size(); + _resources.push_back(ResourceCache(res)); + + return offset; +} + +uint32 Batch::cacheResource(const void* pointer) { + uint32 offset = _resources.size(); + _resources.push_back(ResourceCache(pointer)); + + return offset; +} + +uint32 Batch::cacheData(uint32 size, const void* data) { + uint32 offset = _data.size(); + uint32 nbBytes = size; + _data.resize(offset + nbBytes); + memcpy(_data.data() + offset, data, size); + + return offset; +} + +#define CASE_COMMAND(call) case COMMAND_##call: { do_##call(offset); } break; + +void Batch::runCommand(Command com, uint32 offset) { + switch (com) { + CASE_COMMAND(draw); + CASE_COMMAND(drawIndexed); + CASE_COMMAND(drawInstanced); + CASE_COMMAND(drawIndexedInstanced); + CASE_COMMAND(glEnable); + CASE_COMMAND(glDisable); + CASE_COMMAND(glEnableClientState); + CASE_COMMAND(glDisableClientState); + CASE_COMMAND(glCullFace); + CASE_COMMAND(glAlphaFunc); + CASE_COMMAND(glDepthFunc); + CASE_COMMAND(glDepthMask); + CASE_COMMAND(glDepthRange); + CASE_COMMAND(glBindBuffer); + CASE_COMMAND(glBindTexture); + CASE_COMMAND(glActiveTexture); + CASE_COMMAND(glDrawBuffers); + CASE_COMMAND(glUseProgram); + CASE_COMMAND(glUniform1f); + CASE_COMMAND(glUniformMatrix4fv); + CASE_COMMAND(glMatrixMode); + CASE_COMMAND(glPushMatrix); + CASE_COMMAND(glPopMatrix); + CASE_COMMAND(glMultMatrixf); + CASE_COMMAND(glLoadMatrixf); + CASE_COMMAND(glLoadIdentity); + CASE_COMMAND(glRotatef); + CASE_COMMAND(glScalef); + CASE_COMMAND(glTranslatef); + CASE_COMMAND(glDrawArrays); + CASE_COMMAND(glDrawRangeElements); + CASE_COMMAND(glColorPointer); + CASE_COMMAND(glNormalPointer); + CASE_COMMAND(glTexCoordPointer); + CASE_COMMAND(glVertexPointer); + CASE_COMMAND(glVertexAttribPointer); + CASE_COMMAND(glEnableVertexAttribArray); + CASE_COMMAND(glDisableVertexAttribArray); + CASE_COMMAND(glColor4f); + CASE_COMMAND(glMaterialf); + CASE_COMMAND(glMaterialfv); + } +} + +void Batch::draw(Primitive primitiveType, int nbVertices, int startVertex) { + ADD_COMMAND(draw); + + _params.push_back(startVertex); + _params.push_back(nbVertices); + _params.push_back(primitiveType); +} + +void Batch::drawIndexed(Primitive primitiveType, int nbIndices, int startIndex) { + ADD_COMMAND(drawIndexed); + + _params.push_back(startIndex); + _params.push_back(nbIndices); + _params.push_back(primitiveType); +} + +void Batch::drawInstanced(uint32 nbInstances, Primitive primitiveType, int nbVertices, int startVertex, int startInstance) { + ADD_COMMAND(drawInstanced); + + _params.push_back(startInstance); + _params.push_back(startVertex); + _params.push_back(nbVertices); + _params.push_back(primitiveType); + _params.push_back(nbInstances); +} + +void Batch::drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, int nbIndices, int startIndex, int startInstance) { + ADD_COMMAND(drawIndexedInstanced); + + _params.push_back(startInstance); + _params.push_back(startIndex); + _params.push_back(nbIndices); + _params.push_back(primitiveType); + _params.push_back(nbInstances); +} + +// 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 + +void Batch::_glEnable(GLenum cap) { + ADD_COMMAND(glEnable); + + _params.push_back(cap); + + DO_IT_NOW(_glEnable, 1); +} +void Batch::do_glEnable(uint32 paramOffset) { + glEnable(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glDisable(GLenum cap) { + ADD_COMMAND(glDisable); + + _params.push_back(cap); + + DO_IT_NOW(_glDisable, 1); +} +void Batch::do_glDisable(uint32 paramOffset) { + glDisable(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glEnableClientState(GLenum array) { + ADD_COMMAND(glEnableClientState); + + _params.push_back(array); + + DO_IT_NOW(_glEnableClientState, 1 ); +} +void Batch::do_glEnableClientState(uint32 paramOffset) { + glEnableClientState(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glDisableClientState(GLenum array) { + ADD_COMMAND(glDisableClientState); + + _params.push_back(array); + + DO_IT_NOW(_glDisableClientState, 1); +} +void Batch::do_glDisableClientState(uint32 paramOffset) { + glDisableClientState(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glCullFace(GLenum mode) { + ADD_COMMAND(glCullFace); + + _params.push_back(mode); + + DO_IT_NOW(_glCullFace, 1); +} +void Batch::do_glCullFace(uint32 paramOffset) { + glCullFace(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glAlphaFunc(GLenum func, GLclampf ref) { + ADD_COMMAND(glAlphaFunc); + + _params.push_back(ref); + _params.push_back(func); + + DO_IT_NOW(_glAlphaFunc, 2); +} +void Batch::do_glAlphaFunc(uint32 paramOffset) { + glAlphaFunc( + _params[paramOffset + 1]._uint, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); +} + +void Batch::_glDepthFunc(GLenum func) { + ADD_COMMAND(glDepthFunc); + + _params.push_back(func); + + DO_IT_NOW(_glDepthFunc, 1); +} +void Batch::do_glDepthFunc(uint32 paramOffset) { + glDepthFunc(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glDepthMask(GLboolean flag) { + ADD_COMMAND(glDepthMask); + + _params.push_back(flag); + + DO_IT_NOW(_glDepthMask, 1); +} +void Batch::do_glDepthMask(uint32 paramOffset) { + glDepthMask(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glDepthRange(GLclampd zNear, GLclampd zFar) { + ADD_COMMAND(glDepthRange); + + _params.push_back(zFar); + _params.push_back(zNear); + + DO_IT_NOW(_glDepthRange, 2); +} +void Batch::do_glDepthRange(uint32 paramOffset) { + glDepthRange( + _params[paramOffset + 1]._double, + _params[paramOffset + 0]._double); + CHECK_GL_ERROR(); +} + +void Batch::_glBindBuffer(GLenum target, GLuint buffer) { + ADD_COMMAND(glBindBuffer); + + _params.push_back(buffer); + _params.push_back(target); + + DO_IT_NOW(_glBindBuffer, 2); +} +void Batch::do_glBindBuffer(uint32 paramOffset) { + glBindBuffer( + _params[paramOffset + 1]._uint, + _params[paramOffset + 0]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glBindTexture(GLenum target, GLuint texture) { + ADD_COMMAND(glBindTexture); + + _params.push_back(texture); + _params.push_back(target); + + DO_IT_NOW(_glBindTexture, 2); +} +void Batch::do_glBindTexture(uint32 paramOffset) { + glBindTexture( + _params[paramOffset + 1]._uint, + _params[paramOffset + 0]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glActiveTexture(GLenum texture) { + ADD_COMMAND(glActiveTexture); + + _params.push_back(texture); + + DO_IT_NOW(_glActiveTexture, 1); +} +void Batch::do_glActiveTexture(uint32 paramOffset) { + glActiveTexture(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glDrawBuffers(GLsizei n, const GLenum* bufs) { + ADD_COMMAND(glDrawBuffers); + + _params.push_back(cacheData(n * sizeof(GLenum), bufs)); + _params.push_back(n); + + DO_IT_NOW(_glDrawBuffers, 2); +} +void Batch::do_glDrawBuffers(uint32 paramOffset) { + glDrawBuffers( + _params[paramOffset + 1]._uint, + (const GLenum*) editData(_params[paramOffset + 0]._uint)); + CHECK_GL_ERROR(); +} + +void Batch::_glUseProgram(GLuint program) { + ADD_COMMAND(glUseProgram); + + _params.push_back(program); + + DO_IT_NOW(_glUseProgram, 1); +} +void Batch::do_glUseProgram(uint32 paramOffset) { + glUseProgram(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glUniform1f(GLint location, GLfloat v0) { + ADD_COMMAND(glUniform1f); + + _params.push_back(v0); + _params.push_back(location); + + DO_IT_NOW(_glUniform1f, 1); +} +void Batch::do_glUniform1f(uint32 paramOffset) { + glUniform1f( + _params[paramOffset + 1]._int, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); +} + +void Batch::_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + ADD_COMMAND(glUniformMatrix4fv); + + const int MATRIX4_SIZE = 16 * sizeof(float); + _params.push_back(cacheData(count * MATRIX4_SIZE, value)); + _params.push_back(transpose); + _params.push_back(count); + _params.push_back(location); + + DO_IT_NOW(_glUniformMatrix4fv, 4); +} +void Batch::do_glUniformMatrix4fv(uint32 paramOffset) { + glUniformMatrix4fv( + _params[paramOffset + 3]._int, + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._uint, + (const GLfloat*) editData(_params[paramOffset + 0]._uint)); + CHECK_GL_ERROR(); +} + +void Batch::_glMatrixMode(GLenum mode) { + ADD_COMMAND(glMatrixMode); + + _params.push_back(mode); + + DO_IT_NOW(_glMatrixMode, 1); +} +void Batch::do_glMatrixMode(uint32 paramOffset) { + glMatrixMode(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glPushMatrix() { + ADD_COMMAND(glPushMatrix); + + DO_IT_NOW(_glPushMatrix, 0); +} +void Batch::do_glPushMatrix(uint32 paramOffset) { + glPushMatrix(); + CHECK_GL_ERROR(); +} + +void Batch::_glPopMatrix() { + ADD_COMMAND(glPopMatrix); + + DO_IT_NOW(_glPopMatrix, 0); +} +void Batch::do_glPopMatrix(uint32 paramOffset) { + glPopMatrix(); + CHECK_GL_ERROR(); +} + +void Batch::_glMultMatrixf(const GLfloat *m) { + ADD_COMMAND(glMultMatrixf); + + const int MATRIX4_SIZE = 16 * sizeof(float); + _params.push_back(cacheData(MATRIX4_SIZE, m)); + + DO_IT_NOW(_glMultMatrixf, 1); +} +void Batch::do_glMultMatrixf(uint32 paramOffset) { + glMultMatrixf((const GLfloat*) editData(_params[paramOffset]._uint)); + CHECK_GL_ERROR(); +} + +void Batch::_glLoadMatrixf(const GLfloat *m) { + ADD_COMMAND(glLoadMatrixf); + + const int MATRIX4_SIZE = 16 * sizeof(float); + _params.push_back(cacheData(MATRIX4_SIZE, m)); + + DO_IT_NOW(_glLoadMatrixf, 1); +} +void Batch::do_glLoadMatrixf(uint32 paramOffset) { + glLoadMatrixf((const GLfloat*)editData(_params[paramOffset]._uint)); + CHECK_GL_ERROR(); +} + +void Batch::_glLoadIdentity(void) { + ADD_COMMAND(glLoadIdentity); + + DO_IT_NOW(_glLoadIdentity, 0); +} +void Batch::do_glLoadIdentity(uint32 paramOffset) { + glLoadIdentity(); + CHECK_GL_ERROR(); +} + +void Batch::_glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { + ADD_COMMAND(glRotatef); + + _params.push_back(z); + _params.push_back(y); + _params.push_back(x); + _params.push_back(angle); + + DO_IT_NOW(_glRotatef, 4); +} +void Batch::do_glRotatef(uint32 paramOffset) { + glRotatef( + _params[paramOffset + 3]._float, + _params[paramOffset + 2]._float, + _params[paramOffset + 1]._float, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); +} + +void Batch::_glScalef(GLfloat x, GLfloat y, GLfloat z) { + ADD_COMMAND(glScalef); + + _params.push_back(z); + _params.push_back(y); + _params.push_back(x); + + DO_IT_NOW(_glScalef, 3); +} +void Batch::do_glScalef(uint32 paramOffset) { + glScalef( + _params[paramOffset + 2]._float, + _params[paramOffset + 1]._float, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); +} + +void Batch::_glTranslatef(GLfloat x, GLfloat y, GLfloat z) { + ADD_COMMAND(glTranslatef); + + _params.push_back(z); + _params.push_back(y); + _params.push_back(x); + + DO_IT_NOW(_glTranslatef, 3); +} +void Batch::do_glTranslatef(uint32 paramOffset) { + glTranslatef( + _params[paramOffset + 2]._float, + _params[paramOffset + 1]._float, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); +} + +void Batch::_glDrawArrays(GLenum mode, GLint first, GLsizei count) { + ADD_COMMAND(glDrawArrays); + + _params.push_back(count); + _params.push_back(first); + _params.push_back(mode); + + DO_IT_NOW(_glDrawArrays, 3); +} +void Batch::do_glDrawArrays(uint32 paramOffset) { + glDrawArrays( + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + _params[paramOffset + 0]._int); + CHECK_GL_ERROR(); +} + +void Batch::_glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices) { + ADD_COMMAND(glDrawRangeElements); + + _params.push_back(cacheResource(indices)); + _params.push_back(type); + _params.push_back(count); + _params.push_back(end); + _params.push_back(start); + _params.push_back(mode); + + DO_IT_NOW(_glDrawRangeElements, 6); +} +void Batch::do_glDrawRangeElements(uint32 paramOffset) { + glDrawRangeElements( + _params[paramOffset + 5]._uint, + _params[paramOffset + 4]._uint, + _params[paramOffset + 3]._uint, + _params[paramOffset + 2]._int, + _params[paramOffset + 1]._uint, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); +} + +void Batch::_glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) { + ADD_COMMAND(glColorPointer); + + _params.push_back(cacheResource(pointer)); + _params.push_back(stride); + _params.push_back(type); + _params.push_back(size); + + DO_IT_NOW(_glColorPointer, 4); +} +void Batch::do_glColorPointer(uint32 paramOffset) { + glColorPointer( + _params[paramOffset + 3]._int, + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); +} + +void Batch::_glNormalPointer(GLenum type, GLsizei stride, const void *pointer) { + ADD_COMMAND(glNormalPointer); + + _params.push_back(cacheResource(pointer)); + _params.push_back(stride); + _params.push_back(type); + + DO_IT_NOW(_glNormalPointer, 3); +} +void Batch::do_glNormalPointer(uint32 paramOffset) { + glNormalPointer( + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); +} + +void Batch::_glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) { + ADD_COMMAND(glTexCoordPointer); + + _params.push_back(cacheResource(pointer)); + _params.push_back(stride); + _params.push_back(type); + _params.push_back(size); + + DO_IT_NOW(_glTexCoordPointer, 4); +} +void Batch::do_glTexCoordPointer(uint32 paramOffset) { + glTexCoordPointer( + _params[paramOffset + 3]._int, + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); +} + +void Batch::_glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) { + ADD_COMMAND(glVertexPointer); + + _params.push_back(cacheResource(pointer)); + _params.push_back(stride); + _params.push_back(type); + _params.push_back(size); + + DO_IT_NOW(_glVertexPointer, 4); +} +void Batch::do_glVertexPointer(uint32 paramOffset) { + glVertexPointer( + _params[paramOffset + 3]._int, + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); +} + + +void Batch::_glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) { + ADD_COMMAND(glVertexAttribPointer); + + _params.push_back(cacheResource(pointer)); + _params.push_back(stride); + _params.push_back(normalized); + _params.push_back(type); + _params.push_back(size); + _params.push_back(index); + + DO_IT_NOW(_glVertexAttribPointer, 6); +} +void Batch::do_glVertexAttribPointer(uint32 paramOffset) { + glVertexAttribPointer( + _params[paramOffset + 5]._uint, + _params[paramOffset + 4]._int, + _params[paramOffset + 3]._uint, + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); +} + +void Batch::_glEnableVertexAttribArray(GLint location) { + ADD_COMMAND(glEnableVertexAttribArray); + + _params.push_back(location); + + DO_IT_NOW(_glEnableVertexAttribArray, 1); +} +void Batch::do_glEnableVertexAttribArray(uint32 paramOffset) { + glEnableVertexAttribArray(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glDisableVertexAttribArray(GLint location) { + ADD_COMMAND(glDisableVertexAttribArray); + + _params.push_back(location); + + DO_IT_NOW(_glDisableVertexAttribArray, 1); +} +void Batch::do_glDisableVertexAttribArray(uint32 paramOffset) { + glDisableVertexAttribArray(_params[paramOffset]._uint); + CHECK_GL_ERROR(); +} + +void Batch::_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { + ADD_COMMAND(glColor4f); + + _params.push_back(alpha); + _params.push_back(blue); + _params.push_back(green); + _params.push_back(red); + + DO_IT_NOW(_glColor4f, 4); +} +void Batch::do_glColor4f(uint32 paramOffset) { + glColor4f( + _params[paramOffset + 3]._float, + _params[paramOffset + 2]._float, + _params[paramOffset + 1]._float, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); +} + +void Batch::_glMaterialf(GLenum face, GLenum pname, GLfloat param) { + ADD_COMMAND(glMaterialf); + + _params.push_back(param); + _params.push_back(pname); + _params.push_back(face); + + DO_IT_NOW(_glMaterialf, 3); +} +void Batch::do_glMaterialf(uint32 paramOffset) { + glMaterialf( + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._uint, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); +} + +void Batch::_glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) { + ADD_COMMAND(glMaterialfv); + + _params.push_back(cacheData(4 * sizeof(float), params)); + _params.push_back(pname); + _params.push_back(face); + + DO_IT_NOW(_glMaterialfv, 3); +} +void Batch::do_glMaterialfv(uint32 paramOffset) { + glMaterialfv( + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._uint, + (const GLfloat*) editData(_params[paramOffset + 0]._uint)); + CHECK_GL_ERROR(); +} + + + +void backend::renderBatch(Batch& batch) { + uint32 numCommands = batch._commands.size(); + Batch::CommandCall* call = batch._commandCalls.data(); + Batch::CommandOffsets::value_type* offset = batch._commandOffsets.data(); + + for (int i = 0; i < numCommands; i++) { + (batch.*(*call))(*offset); + call++; + offset++; + } +} + +void backend::checkGLError() { + GLenum error = glGetError(); + if (!error) { + return; + } else { + switch (error) { + case GL_INVALID_ENUM: + qDebug() << "An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag."; + break; + case GL_INVALID_VALUE: + qDebug() << "A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag"; + break; + case GL_INVALID_OPERATION: + qDebug() << "The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag.."; + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + qDebug() << "The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag."; + break; + case GL_OUT_OF_MEMORY: + qDebug() << "There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded."; + break; + case GL_STACK_UNDERFLOW: + qDebug() << "An attempt has been made to perform an operation that would cause an internal stack to underflow."; + break; + case GL_STACK_OVERFLOW: + qDebug() << "An attempt has been made to perform an operation that would cause an internal stack to overflow."; + break; + } + } +} \ No newline at end of file diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h new file mode 100644 index 0000000000..ad5246f9b6 --- /dev/null +++ b/interface/src/gpu/Batch.h @@ -0,0 +1,318 @@ +// +// Batch.h +// interface/src/gpu +// +// Created by Sam Gateau on 10/14/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_Batch_h +#define hifi_gpu_Batch_h + +#include +#include "InterfaceConfig.h" + +#include + +namespace gpu { + +class Batch; +// TODO: move the backend namespace into dedicated files, for now we keep it close to the gpu objects definition for convenience +namespace backend { + + void renderBatch(Batch& batch); + + void checkGLError(); +}; + +class Buffer; +class Resource; +typedef int Stamp; +typedef unsigned int uint32; +typedef int int32; + +enum Primitive { + PRIMITIVE_POINTS = 0, + PRIMITIVE_LINES, + PRIMITIVE_LINE_STRIP, + PRIMITIVE_TRIANGLES, + PRIMITIVE_TRIANGLE_STRIP, + PRIMITIVE_QUADS, +}; + +class Batch { +public: + + Batch(); + Batch(const Batch& batch); + ~Batch(); + + void clear(); + + void draw(Primitive primitiveType, int nbVertices, int startVertex = 0); + void drawIndexed(Primitive primitiveType, int nbIndices, int startIndex = 0); + void drawInstanced(uint32 nbInstances, Primitive primitiveType, int nbVertices, int startVertex = 0, int startInstance = 0); + void drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, int nbIndices, int startIndex = 0, int startInstance = 0); + + // 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 + void _glEnable(GLenum cap); + void _glDisable(GLenum cap); + + void _glEnableClientState(GLenum array); + void _glDisableClientState(GLenum array); + + void _glCullFace(GLenum mode); + void _glAlphaFunc(GLenum func, GLclampf ref); + + void _glDepthFunc(GLenum func); + void _glDepthMask(GLboolean flag); + void _glDepthRange(GLclampd zNear, GLclampd zFar); + + void _glBindBuffer(GLenum target, GLuint buffer); + + void _glBindTexture(GLenum target, GLuint texture); + void _glActiveTexture(GLenum texture); + + void _glDrawBuffers(GLsizei n, const GLenum* bufs); + + void _glUseProgram(GLuint program); + void _glUniform1f(GLint location, GLfloat v0); + void _glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + + void _glMatrixMode(GLenum mode); + void _glPushMatrix(); + void _glPopMatrix(); + void _glMultMatrixf(const GLfloat *m); + void _glLoadMatrixf(const GLfloat *m); + void _glLoadIdentity(void); + void _glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); + void _glScalef(GLfloat x, GLfloat y, GLfloat z); + void _glTranslatef(GLfloat x, GLfloat y, GLfloat z); + + void _glDrawArrays(GLenum mode, GLint first, GLsizei count); + void _glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); + + void _glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); + void _glNormalPointer(GLenum type, GLsizei stride, const void *pointer); + void _glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); + void _glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); + + void _glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); + void _glEnableVertexAttribArray(GLint location); + void _glDisableVertexAttribArray(GLint location); + + void _glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + + void _glMaterialf(GLenum face, GLenum pname, GLfloat param); + void _glMaterialfv(GLenum face, GLenum pname, const GLfloat *params); + + +protected: + + enum Command { + COMMAND_draw = 0, + COMMAND_drawIndexed, + COMMAND_drawInstanced, + COMMAND_drawIndexedInstanced, + + COMMAND_SET_PIPE_STATE, + COMMAND_SET_VIEWPORT, + COMMAND_SET_FRAMEBUFFER, + COMMAND_SET_RESOURCE, + COMMAND_SET_VERTEX_STREAM, + COMMAND_SET_INDEX_STREAM, + + // 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 + COMMAND_glEnable, + COMMAND_glDisable, + + COMMAND_glEnableClientState, + COMMAND_glDisableClientState, + + COMMAND_glCullFace, + COMMAND_glAlphaFunc, + + COMMAND_glDepthFunc, + COMMAND_glDepthMask, + COMMAND_glDepthRange, + + COMMAND_glBindBuffer, + + COMMAND_glBindTexture, + COMMAND_glActiveTexture, + + COMMAND_glDrawBuffers, + + COMMAND_glUseProgram, + COMMAND_glUniform1f, + COMMAND_glUniformMatrix4fv, + + COMMAND_glMatrixMode, + COMMAND_glPushMatrix, + COMMAND_glPopMatrix, + COMMAND_glMultMatrixf, + COMMAND_glLoadMatrixf, + COMMAND_glLoadIdentity, + COMMAND_glRotatef, + COMMAND_glScalef, + COMMAND_glTranslatef, + + COMMAND_glDrawArrays, + COMMAND_glDrawRangeElements, + + COMMAND_glColorPointer, + COMMAND_glNormalPointer, + COMMAND_glTexCoordPointer, + COMMAND_glVertexPointer, + + COMMAND_glVertexAttribPointer, + COMMAND_glEnableVertexAttribArray, + COMMAND_glDisableVertexAttribArray, + + COMMAND_glColor4f, + + COMMAND_glMaterialf, + COMMAND_glMaterialfv, + }; + typedef std::vector Commands; + typedef void (Batch::*CommandCall)(uint32); + typedef std::vector CommandCalls; + typedef std::vector CommandOffsets; + + + class Param { + public: + union { + int32 _int; + uint32 _uint; + float _float; + char _chars[4]; + double _double; + }; + Param(int32 val) : _int(val) {} + Param(uint32 val) : _uint(val) {} + Param(float val) : _float(val) {} + Param(double val) : _double(val) {} + }; + typedef std::vector Params; + + class ResourceCache { + public: + union { + Resource* _resource; + const void* _pointer; + }; + ResourceCache(Resource* res) : _resource(res) {} + ResourceCache(const void* pointer) : _pointer(pointer) {} + }; + typedef std::vector Resources; + + typedef unsigned char Byte; + typedef std::vector Bytes; + + Commands _commands; + CommandCalls _commandCalls; + CommandOffsets _commandOffsets; + Params _params; + Resources _resources; + Bytes _data; + + uint32 cacheResource(Resource* res); + uint32 cacheResource(const void* pointer); + ResourceCache* editResource(uint32 offset) { + if (offset >= _resources.size()) + return 0; + return (_resources.data() + offset); + } + + uint32 cacheData(uint32 size, const void* data); + Byte* editData(uint32 offset) { + if (offset >= _data.size()) + return 0; + return (_data.data() + offset); + } + + void runCommand(uint32 index) { + uint32 offset = _commandOffsets[index]; + CommandCall call = _commandCalls[index]; + (this->*(call))(offset); + } + + void runLastCommand() { + uint32 index = _commands.size() - 1; + runCommand(index); + } + + void runCommand(Command com, uint32 offset); + + void do_draw(uint32 paramOffset) {} + void do_drawIndexed(uint32 paramOffset) {} + void do_drawInstanced(uint32 paramOffset) {} + void do_drawIndexedInstanced(uint32 paramOffset) {} + + // 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 + void do_glEnable(uint32 paramOffset); + void do_glDisable(uint32 paramOffset); + + void do_glEnableClientState(uint32 paramOffset); + void do_glDisableClientState(uint32 paramOffset); + + void do_glCullFace(uint32 paramOffset); + void do_glAlphaFunc(uint32 paramOffset); + + void do_glDepthFunc(uint32 paramOffset); + void do_glDepthMask(uint32 paramOffset); + void do_glDepthRange(uint32 paramOffset); + + void do_glBindBuffer(uint32 paramOffset); + + void do_glBindTexture(uint32 paramOffset); + void do_glActiveTexture(uint32 paramOffset); + + void do_glDrawBuffers(uint32 paramOffset); + + void do_glUseProgram(uint32 paramOffset); + void do_glUniform1f(uint32 paramOffset); + void do_glUniformMatrix4fv(uint32 paramOffset); + + void do_glMatrixMode(uint32 paramOffset); + void do_glPushMatrix(uint32 paramOffset); + void do_glPopMatrix(uint32 paramOffset); + void do_glMultMatrixf(uint32 paramOffset); + void do_glLoadMatrixf(uint32 paramOffset); + void do_glLoadIdentity(uint32 paramOffset); + void do_glRotatef(uint32 paramOffset); + void do_glScalef(uint32 paramOffset); + void do_glTranslatef(uint32 paramOffset); + + void do_glDrawArrays(uint32 paramOffset); + void do_glDrawRangeElements(uint32 paramOffset); + + void do_glColorPointer(uint32 paramOffset); + void do_glNormalPointer(uint32 paramOffset); + void do_glTexCoordPointer(uint32 paramOffset); + void do_glVertexPointer(uint32 paramOffset); + + void do_glVertexAttribPointer(uint32 paramOffset); + void do_glEnableVertexAttribArray(uint32 paramOffset); + void do_glDisableVertexAttribArray(uint32 paramOffset); + + void do_glColor4f(uint32 paramOffset); + + void do_glMaterialf(uint32 paramOffset); + void do_glMaterialfv(uint32 paramOffset); + + friend void backend::renderBatch(Batch& batch); +}; + +}; + +#endif diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 3800e78008..131c600dc1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -26,6 +26,10 @@ #include "Application.h" #include "Model.h" +#include "gpu/Batch.h" +#define GLBATCH( call ) batch._##call +//#define GLBATCH( call ) call + using namespace std; static int modelPointerTypeId = qRegisterMetaType >(); @@ -430,97 +434,135 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { segregateMeshGroups(); } - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - glDisable(GL_COLOR_MATERIAL); + // Let's introduce a gpu::Batch to capture all the calls to the graphics api + gpu::Batch batch; + + GLBATCH(glEnableClientState)(GL_VERTEX_ARRAY); + GLBATCH(glEnableClientState)(GL_NORMAL_ARRAY); + + GLBATCH(glDisable)(GL_COLOR_MATERIAL); if (mode == DIFFUSE_RENDER_MODE || mode == NORMAL_RENDER_MODE) { - glDisable(GL_CULL_FACE); + GLBATCH(glDisable)(GL_CULL_FACE); } else { - glEnable(GL_CULL_FACE); + GLBATCH(glEnable)(GL_CULL_FACE); if (mode == SHADOW_RENDER_MODE) { - glCullFace(GL_FRONT); + GLBATCH(glCullFace)(GL_FRONT); } } // render opaque meshes with alpha testing - - glDisable(GL_BLEND); - glEnable(GL_ALPHA_TEST); + + GLBATCH(glDisable)(GL_BLEND); + GLBATCH(glEnable)(GL_ALPHA_TEST); if (mode == SHADOW_RENDER_MODE) { - glAlphaFunc(GL_EQUAL, 0.0f); + GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f); } - - Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers( + + + /*Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers( mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE, mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE, mode == DEFAULT_RENDER_MODE); - + */ + { + GLenum buffers[3]; + int bufferCount = 0; + if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; + } + if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE) { + buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; + } + if (mode == DEFAULT_RENDER_MODE) { + buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; + } + GLBATCH(glDrawBuffers)(bufferCount, buffers); + } + const float DEFAULT_ALPHA_THRESHOLD = 0.5f; + //renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, book isSkinned, args); int opaqueMeshPartsRendered = 0; - opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); - opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args); - opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args); - opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args); - opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); - opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); - opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); - opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); - + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); + // render translucent meshes afterwards - Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true); + //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true); + { + GLenum buffers[2]; + int bufferCount = 0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; + GLBATCH(glDrawBuffers)(bufferCount, buffers); + } + int translucentMeshPartsRendered = 0; const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); - - glDisable(GL_ALPHA_TEST); - glEnable(GL_BLEND); - glDepthMask(false); - glDepthFunc(GL_LEQUAL); - - Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + + GLBATCH(glDisable)(GL_ALPHA_TEST); + GLBATCH(glEnable)(GL_BLEND); + GLBATCH(glDepthMask)(false); + GLBATCH(glDepthFunc)(GL_LEQUAL); + //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true); + { + GLenum buffers[1]; + int bufferCount = 0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; + GLBATCH(glDrawBuffers)(bufferCount, buffers); + } + if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); - translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); } - - glDepthMask(true); - glDepthFunc(GL_LESS); - glDisable(GL_CULL_FACE); + + GLBATCH(glDepthMask)(true); + GLBATCH(glDepthFunc)(GL_LESS); + GLBATCH(glDisable)(GL_CULL_FACE); if (mode == SHADOW_RENDER_MODE) { - glCullFace(GL_BACK); + GLBATCH(glCullFace)(GL_BACK); } - + // deactivate vertex arrays after drawing - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + GLBATCH(glDisableClientState)(GL_NORMAL_ARRAY); + GLBATCH(glDisableClientState)(GL_VERTEX_ARRAY); + GLBATCH(glDisableClientState)(GL_TEXTURE_COORD_ARRAY); // bind with 0 to switch back to normal operation - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - + GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, 0); + GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, 0); + GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); + + // Render! + ::gpu::backend::renderBatch(batch); + batch.clear(); + // restore all the default material settings Application::getInstance()->setupWorldLight(); @@ -1506,7 +1548,7 @@ void Model::segregateMeshGroups() { _meshGroupsKnown = true; } -int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, +int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { bool dontCullOutOfViewMeshParts = Menu::getInstance()->isOptionChecked(MenuOption::DontCullOutOfViewMeshParts); @@ -1606,16 +1648,21 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, ProgramObject* activeProgram = program; Locations* activeLocations = locations; - + if (isSkinned) { - skinProgram->bind(); activeProgram = skinProgram; activeLocations = skinLocations; - } else { - program->bind(); } - activeProgram->setUniformValue(activeLocations->alphaThreshold, alphaThreshold); - + // This code replace the "bind()" on the QGLProgram + if (!activeProgram->isLinked()) { + activeProgram->link(); + } + GLBATCH(glUseProgram)(activeProgram->programId()); + // activeProgram->setUniformValue(activeLocations->alphaThreshold, alphaThreshold); + GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold); + + + // i is the "index" from the original networkMeshes QVector... foreach (int i, list) { @@ -1631,7 +1678,8 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, const NetworkMesh& networkMesh = networkMeshes.at(i); const FBXMesh& mesh = geometry.meshes.at(i); - const_cast(networkMesh.indexBuffer).bind(); + //const_cast(networkMesh.indexBuffer).bind(); + GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, const_cast(networkMesh.indexBuffer).bufferId()); int vertexCount = mesh.vertices.size(); if (vertexCount == 0) { @@ -1666,56 +1714,70 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, } } - const_cast(networkMesh.vertexBuffer).bind(); - - glPushMatrix(); - Application::getInstance()->loadTranslatedViewMatrix(_translation); + //const_cast(networkMesh.vertexBuffer).bind(); + GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, const_cast(networkMesh.vertexBuffer).bufferId()); + + GLBATCH(glPushMatrix)(); + //Application::getInstance()->loadTranslatedViewMatrix(_translation); + GLBATCH(glLoadMatrixf)((const GLfloat*)&Application::getInstance()->getUntranslatedViewMatrix()); + glm::vec3 viewMatTranslation = Application::getInstance()->getViewMatrixTranslation(); + GLBATCH(glTranslatef)(_translation.x + viewMatTranslation.x, _translation.y + viewMatTranslation.y, + _translation.z + viewMatTranslation.z); const MeshState& state = _meshStates.at(i); if (state.clusterMatrices.size() > 1) { - glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, + GLBATCH(glUniformMatrix4fv)(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) + mesh.texCoords.size() * sizeof(glm::vec2) + (mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0); - skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4); - skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT, - offset + vertexCount * sizeof(glm::vec4), 4); - skinProgram->enableAttributeArray(skinLocations->clusterIndices); - skinProgram->enableAttributeArray(skinLocations->clusterWeights); + //skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4); + GLBATCH(glVertexAttribPointer)(skinLocations->clusterIndices, 4, GL_FLOAT, GL_TRUE, 0, (const void*) offset); + //skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT, + // offset + vertexCount * sizeof(glm::vec4), 4); + GLBATCH(glVertexAttribPointer)(skinLocations->clusterWeights, 4, GL_FLOAT, GL_TRUE, 0, (const void*) (offset + vertexCount * sizeof(glm::vec4))); + //skinProgram->enableAttributeArray(skinLocations->clusterIndices); + GLBATCH(glEnableVertexAttribArray)(skinLocations->clusterIndices); + //skinProgram->enableAttributeArray(skinLocations->clusterWeights); + GLBATCH(glEnableVertexAttribArray)(skinLocations->clusterWeights); } else { - glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); + GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); } if (mesh.blendshapes.isEmpty()) { if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { - activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); - activeProgram->enableAttributeArray(activeLocations->tangent); + //activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); + GLBATCH(glVertexAttribPointer)(activeLocations->tangent, 3, GL_FLOAT, GL_TRUE, 0, (const void*)(vertexCount * 2 * sizeof(glm::vec3))); + //activeProgram->enableAttributeArray(activeLocations->tangent); + GLBATCH(glEnableVertexAttribArray)(activeLocations->tangent); } - glColorPointer(3, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) + + GLBATCH(glColorPointer)(3, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) + mesh.tangents.size() * sizeof(glm::vec3))); - glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) + + GLBATCH(glTexCoordPointer)(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) + (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); } else { if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { - activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, 0, 3); - activeProgram->enableAttributeArray(activeLocations->tangent); + //activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, 0, 3); + GLBATCH(glVertexAttribPointer)(activeLocations->tangent, 3, GL_FLOAT, GL_TRUE, 0, 0); + //activeProgram->enableAttributeArray(activeLocations->tangent); + GLBATCH(glEnableVertexAttribArray)(activeLocations->tangent); } - glColorPointer(3, GL_FLOAT, 0, (void*)(mesh.tangents.size() * sizeof(glm::vec3))); - glTexCoordPointer(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); - _blendedVertexBuffers[i].bind(); + GLBATCH(glColorPointer)(3, GL_FLOAT, 0, (void*)(mesh.tangents.size() * sizeof(glm::vec3))); + GLBATCH(glTexCoordPointer)(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); + // _blendedVertexBuffers[i].bind(); + GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, _blendedVertexBuffers[i].bufferId()); } - glVertexPointer(3, GL_FLOAT, 0, 0); - glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); + GLBATCH(glVertexPointer)(3, GL_FLOAT, 0, 0); + GLBATCH(glNormalPointer)(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); if (!mesh.colors.isEmpty()) { - glEnableClientState(GL_COLOR_ARRAY); + GLBATCH(glEnableClientState)(GL_COLOR_ARRAY); } else { - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GLBATCH(glColor4f)(1.0f, 1.0f, 1.0f, 1.0f); } if (!mesh.texCoords.isEmpty()) { - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + GLBATCH(glEnableClientState)(GL_TEXTURE_COORD_ARRAY); } qint64 offset = 0; @@ -1726,9 +1788,10 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, offset += (part.quadIndices.size() + part.triangleIndices.size()) * sizeof(int); continue; } + // apply material properties if (mode == SHADOW_RENDER_MODE) { - glBindTexture(GL_TEXTURE_2D, 0); + GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); } else { if (dontReduceMaterialSwitches || lastMaterialID != part.materialID) { @@ -1741,36 +1804,36 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, glm::vec4 diffuse = glm::vec4(part.diffuseColor, part.opacity); if (!(translucent && alphaThreshold == 0.0f)) { - glAlphaFunc(GL_EQUAL, diffuse.a = Application::getInstance()->getGlowEffect()->getIntensity()); + GLBATCH(glAlphaFunc)(GL_EQUAL, diffuse.a = Application::getInstance()->getGlowEffect()->getIntensity()); } glm::vec4 specular = glm::vec4(part.specularColor, 1.0f); - glMaterialfv(GL_FRONT, GL_AMBIENT, (const float*)&diffuse); - glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse); - glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular); - glMaterialf(GL_FRONT, GL_SHININESS, part.shininess); + GLBATCH(glMaterialfv)(GL_FRONT, GL_AMBIENT, (const float*)&diffuse); + GLBATCH(glMaterialfv)(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse); + GLBATCH(glMaterialfv)(GL_FRONT, GL_SPECULAR, (const float*)&specular); + GLBATCH(glMaterialf)(GL_FRONT, GL_SHININESS, (part.shininess > 128.f ? 128.f: part.shininess)); Texture* diffuseMap = networkPart.diffuseTexture.data(); if (mesh.isEye && diffuseMap) { diffuseMap = (_dilatedTextures[i][j] = static_cast(diffuseMap)->getDilatedTexture(_pupilDilation)).data(); } - glBindTexture(GL_TEXTURE_2D, !diffuseMap ? + GLBATCH(glBindTexture)(GL_TEXTURE_2D, !diffuseMap ? Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID()); if (!mesh.tangents.isEmpty()) { - glActiveTexture(GL_TEXTURE1); + GLBATCH(glActiveTexture)(GL_TEXTURE1); Texture* normalMap = networkPart.normalTexture.data(); - glBindTexture(GL_TEXTURE_2D, !normalMap ? + GLBATCH(glBindTexture)(GL_TEXTURE_2D, !normalMap ? Application::getInstance()->getTextureCache()->getBlueTextureID() : normalMap->getID()); - glActiveTexture(GL_TEXTURE0); + GLBATCH(glActiveTexture)(GL_TEXTURE0); } if (specularTextureUnit) { - glActiveTexture(specularTextureUnit); + GLBATCH(glActiveTexture)(specularTextureUnit); Texture* specularMap = networkPart.specularTexture.data(); - glBindTexture(GL_TEXTURE_2D, !specularMap ? + GLBATCH(glBindTexture)(GL_TEXTURE_2D, !specularMap ? Application::getInstance()->getTextureCache()->getWhiteTextureID() : specularMap->getID()); - glActiveTexture(GL_TEXTURE0); + GLBATCH(glActiveTexture)(GL_TEXTURE0); } if (args) { args->_materialSwitches++; @@ -1783,12 +1846,12 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, meshPartsRendered++; if (part.quadIndices.size() > 0) { - glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset); + GLBATCH(glDrawRangeElements)(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset); offset += part.quadIndices.size() * sizeof(int); } if (part.triangleIndices.size() > 0) { - glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(), + GLBATCH(glDrawRangeElements)(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(), GL_UNSIGNED_INT, (void*)offset); offset += part.triangleIndices.size() * sizeof(int); } @@ -1802,35 +1865,39 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, } if (!mesh.colors.isEmpty()) { - glDisableClientState(GL_COLOR_ARRAY); + GLBATCH(glDisableClientState)(GL_COLOR_ARRAY); } if (!mesh.texCoords.isEmpty()) { - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + GLBATCH(glDisableClientState)(GL_TEXTURE_COORD_ARRAY); } if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); + GLBATCH(glActiveTexture)(GL_TEXTURE1); + GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); + GLBATCH(glActiveTexture)(GL_TEXTURE0); - activeProgram->disableAttributeArray(activeLocations->tangent); + // activeProgram->disableAttributeArray(activeLocations->tangent); + GLBATCH(glDisableVertexAttribArray)(activeLocations->tangent); } if (specularTextureUnit) { - glActiveTexture(specularTextureUnit); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); + GLBATCH(glActiveTexture)(specularTextureUnit); + GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); + GLBATCH(glActiveTexture)(GL_TEXTURE0); } if (state.clusterMatrices.size() > 1) { - skinProgram->disableAttributeArray(skinLocations->clusterIndices); - skinProgram->disableAttributeArray(skinLocations->clusterWeights); + // skinProgram->disableAttributeArray(skinLocations->clusterIndices); + GLBATCH(glDisableVertexAttribArray)(skinLocations->clusterIndices); + // skinProgram->disableAttributeArray(skinLocations->clusterWeights); + GLBATCH(glDisableVertexAttribArray)(skinLocations->clusterWeights); } - glPopMatrix(); + GLBATCH(glPopMatrix)(); } - activeProgram->release(); - + //activeProgram->release(); + GLBATCH(glUseProgram)(0); + return meshPartsRendered; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 86fa0c2b7a..b6c9987807 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -36,6 +36,10 @@ class ViewFrustum; typedef QSharedPointer AnimationHandlePointer; typedef QWeakPointer WeakAnimationHandlePointer; +namespace gpu { + class Batch; +} + /// A generic 3D model displaying geometry loaded from a URL. class Model : public QObject, public PhysicsEntity { Q_OBJECT @@ -252,7 +256,7 @@ private: void applyNextGeometry(); void deleteGeometry(); - int renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL); + int renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL); QVector createJointStates(const FBXGeometry& geometry); void initJointTransforms(); diff --git a/interface/src/ui/DataWebPage.cpp b/interface/src/ui/DataWebPage.cpp index 812489a34d..b8b6649276 100644 --- a/interface/src/ui/DataWebPage.cpp +++ b/interface/src/ui/DataWebPage.cpp @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + +#include #include #include "DataWebPage.h" @@ -19,13 +22,22 @@ DataWebPage::DataWebPage(QObject* parent) : // use an OAuthNetworkAccessManager instead of regular QNetworkAccessManager so our requests are authed setNetworkAccessManager(OAuthNetworkAccessManager::getInstance()); - // have the page delegate external links so they can be captured by the Application in case they are a hifi link - setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); - // give the page an empty stylesheet settings()->setUserStyleSheetUrl(QUrl()); } void DataWebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID) { qDebug() << "JS console message at line" << lineNumber << "from" << sourceID << "-" << message; +} + +bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) { + + if (!request.url().toString().startsWith(HIFI_URL_SCHEME)) { + return true; + } else { + // this is a hifi URL - have the AddressManager handle it + QMetaObject::invokeMethod(&AddressManager::getInstance(), "handleLookupString", + Qt::AutoConnection, Q_ARG(const QString&, request.url().toString())); + return false; + } } \ No newline at end of file diff --git a/interface/src/ui/DataWebPage.h b/interface/src/ui/DataWebPage.h index 72fcbb5992..6d89077a33 100644 --- a/interface/src/ui/DataWebPage.h +++ b/interface/src/ui/DataWebPage.h @@ -19,6 +19,7 @@ public: DataWebPage(QObject* parent = 0); protected: void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID); + bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type); }; #endif // hifi_DataWebPage_h \ No newline at end of file diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index 35a822f11b..47d1b04421 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -212,7 +212,7 @@ void Player::loadRecording(RecordingPointer recording) { void Player::play() { computeCurrentFrame(); - if (_currentFrame < 0 || (_currentFrame >= _recording->getFrameNumber() - 1)) { + if (_currentFrame < 0 || (_currentFrame >= _recording->getFrameNumber() - 2)) { // -2 because of interpolation if (_loop) { loopRecording(); } else { diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 5b00c6531f..2bd28de784 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -2486,8 +2486,39 @@ bool Heightfield::intersects(const glm::vec3& start, const glm::vec3& end, float if (!getBounds().findRayIntersection(start, direction, rayDistance) || rayDistance > 1.0f) { return false; } - glm::vec3 entry = (start + direction * rayDistance - getBounds().minimum) / _increment; - direction /= _increment; + glm::vec3 entry = start + direction * rayDistance; + const float DISTANCE_THRESHOLD = 0.001f; + if (glm::abs(entry.x - getBounds().minimum.x) < DISTANCE_THRESHOLD) { + normal = glm::vec3(-1.0f, 0.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.x - getBounds().maximum.x) < DISTANCE_THRESHOLD) { + normal = glm::vec3(1.0f, 0.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.y - getBounds().minimum.y) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, -1.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.y - getBounds().maximum.y) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, 1.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.z - getBounds().minimum.z) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, 0.0f, -1.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.z - getBounds().maximum.z) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, 0.0f, 1.0f); + distance = rayDistance; + return true; + } + entry = (entry - getBounds().minimum) / _increment; glm::vec3 floors = glm::floor(entry); glm::vec3 ceils = glm::ceil(entry); if (floors.x == ceils.x) { diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index d9c60f3f12..549931e030 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -998,10 +998,13 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { _spannerBounds.maximum = (glm::ceil(_bounds.maximum / increment) + glm::vec3(1.0f, 0.0f, 1.0f)) * increment; _spannerBounds.minimum.y = bounds.minimum.y; _spannerBounds.maximum.y = bounds.maximum.y; - _heightfieldWidth = (int)glm::round((_spannerBounds.maximum.x - _spannerBounds.minimum.x) / increment) + 1; - _heightfieldHeight = (int)glm::round((_spannerBounds.maximum.z - _spannerBounds.minimum.z) / increment) + 1; + _heightfieldWidth = (int)glm::round((_spannerBounds.maximum.x - _spannerBounds.minimum.x) / increment); + _heightfieldHeight = (int)glm::round((_spannerBounds.maximum.z - _spannerBounds.minimum.z) / increment); int heightfieldArea = _heightfieldWidth * _heightfieldHeight; - _spanner = spanner = new Heightfield(_spannerBounds, increment, QByteArray(heightfieldArea, 0), + Box innerBounds = _spannerBounds; + innerBounds.maximum.x -= increment; + innerBounds.maximum.z -= increment; + _spanner = spanner = new Heightfield(innerBounds, increment, QByteArray(heightfieldArea, 0), QByteArray(heightfieldArea * DataBlock::COLOR_BYTES, 0), QByteArray(heightfieldArea, 0), QVector()); } @@ -1049,18 +1052,20 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { } // if all is gone, clear the node - if (!foundNonZero) { - info.outputValues[0] = AttributeValue(_outputs.at(0), - encodeInline(HeightfieldHeightDataPointer())); - info.outputValues[1] = AttributeValue(_outputs.at(1), - encodeInline(HeightfieldColorDataPointer())); - info.outputValues[2] = AttributeValue(_outputs.at(2), - encodeInline(HeightfieldMaterialDataPointer())); - return STOP_RECURSION; + if (foundNonZero) { + HeightfieldHeightDataPointer newHeightPointer(new HeightfieldHeightData(contents)); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newHeightPointer)); + + } else { + info.outputValues[0] = AttributeValue(_outputs.at(0)); } - HeightfieldHeightDataPointer newHeightPointer(new HeightfieldHeightData(contents)); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newHeightPointer)); + // allow a border for what we clear in terms of color/material + innerBounds.minimum.x += increment; + innerBounds.minimum.z += increment; + innerBounds.maximum.x -= increment; + innerBounds.maximum.z -= increment; + innerOverlap = bounds.getIntersection(innerBounds); HeightfieldColorDataPointer colorPointer = info.inputValues.at(1).getInlineValue(); if (colorPointer) { @@ -1083,18 +1088,25 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { memcpy(dest, src, destWidth * DataBlock::COLOR_BYTES); } - destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; - destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; - destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); - destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); - dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES; - - for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) { - memset(dest, 0, destWidth * DataBlock::COLOR_BYTES); + if (foundNonZero) { + destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; + destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; + destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); + destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); + if (destWidth > 0 && destHeight > 0) { + dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES; + + for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) { + memset(dest, 0, destWidth * DataBlock::COLOR_BYTES); + } + + HeightfieldColorDataPointer newColorPointer(new HeightfieldColorData(contents)); + info.outputValues[1] = AttributeValue(_outputs.at(1), + encodeInline(newColorPointer)); + } + } else { + info.outputValues[1] = AttributeValue(_outputs.at(1)); } - - HeightfieldColorDataPointer newColorPointer(new HeightfieldColorData(contents)); - info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline(newColorPointer)); } HeightfieldMaterialDataPointer materialPointer = info.inputValues.at(2).getInlineValue(); @@ -1130,20 +1142,26 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { } } - destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; - destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; - destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); - destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); - dest = (uchar*)contents.data() + destY * size + destX; - - for (int y = 0; y < destHeight; y++, dest += size) { - memset(dest, 0, destWidth); + if (foundNonZero) { + destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; + destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; + destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); + destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); + if (destWidth > 0 && destHeight > 0) { + dest = (uchar*)contents.data() + destY * size + destX; + + for (int y = 0; y < destHeight; y++, dest += size) { + memset(dest, 0, destWidth); + } + + clearUnusedMaterials(materials, contents); + HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials)); + info.outputValues[2] = AttributeValue(_outputs.at(2), + encodeInline(newMaterialPointer)); + } + } else { + info.outputValues[2] = AttributeValue(_outputs.at(2)); } - - clearUnusedMaterials(materials, contents); - HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials)); - info.outputValues[2] = AttributeValue(_outputs.at(2), - encodeInline(newMaterialPointer)); } return STOP_RECURSION;