Merge pull request #3642 from samcake/temp0

Bring back the GL batching for model rendering and fixed the bug on MAC
This commit is contained in:
Andrzej Kapolka 2014-10-23 17:54:45 -07:00
commit 3d6d418548
4 changed files with 1265 additions and 123 deletions

753
interface/src/gpu/Batch.cpp Normal file
View file

@ -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 <QDebug>
#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;
}
}
}

318
interface/src/gpu/Batch.h Normal file
View file

@ -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 <assert.h>
#include "InterfaceConfig.h"
#include <vector>
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<Command> Commands;
typedef void (Batch::*CommandCall)(uint32);
typedef std::vector<CommandCall> CommandCalls;
typedef std::vector<uint32> 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<Param> Params;
class ResourceCache {
public:
union {
Resource* _resource;
const void* _pointer;
};
ResourceCache(Resource* res) : _resource(res) {}
ResourceCache(const void* pointer) : _pointer(pointer) {}
};
typedef std::vector<ResourceCache> Resources;
typedef unsigned char Byte;
typedef std::vector<Byte> 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

View file

@ -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<QPointer<Model> >();
@ -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<QOpenGLBuffer&>(networkMesh.indexBuffer).bind();
//const_cast<QOpenGLBuffer&>(networkMesh.indexBuffer).bind();
GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, const_cast<QOpenGLBuffer&>(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<QOpenGLBuffer&>(networkMesh.vertexBuffer).bind();
glPushMatrix();
Application::getInstance()->loadTranslatedViewMatrix(_translation);
//const_cast<QOpenGLBuffer&>(networkMesh.vertexBuffer).bind();
GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, const_cast<QOpenGLBuffer&>(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<DilatableNetworkTexture*>(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;
}

View file

@ -36,6 +36,10 @@ class ViewFrustum;
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
typedef QWeakPointer<AnimationHandle> 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<JointState> createJointStates(const FBXGeometry& geometry);
void initJointTransforms();