bullet3/btgui/OpenGLWindow/GLInstancingRenderer.cpp

1339 lines
35 KiB
C++

/*
Copyright (c) 2012 Advanced Micro Devices, Inc.
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
//Originally written by Erwin Coumans
#include "OpenGLInclude.h"
#include "GLInstancingRenderer.h"
#include <string.h>
//#include "DemoSettings.h"
#include <stdio.h>
#include <assert.h>
#include "Bullet3Common/b3Vector3.h"
#include "Bullet3Common/b3Quaternion.h"
#include "Bullet3Common/b3Quickprof.h"
#include "Bullet3Common/b3Matrix3x3.h"
#include "LoadShader.h"
//#include "../../opencl/gpu_rigidbody_pipeline/b3GpuNarrowphaseAndSolver.h"//for m_maxNumObjectCapacity
static InternalDataRenderer* sData2;
struct b3GraphicsInstance
{
GLuint m_cube_vao;
GLuint m_index_vbo;
GLuint m_texturehandle;
int m_numIndices;
int m_numVertices;
int m_numGraphicsInstances;
int m_instanceOffset;
int m_vertexArrayOffset;
int m_primitiveType;
b3GraphicsInstance() :m_cube_vao(-1),m_index_vbo(-1),m_numIndices(-1),m_numVertices(-1),m_numGraphicsInstances(0),m_instanceOffset(0),m_vertexArrayOffset(0),m_primitiveType(B3_GL_TRIANGLES),m_texturehandle(0)
{
}
};
bool m_ortho = false;
int m_glutScreenWidth = 1024;
int m_glutScreenHeight = 768;
static GLfloat projectionMatrix[16];
static GLfloat modelviewMatrix[16];
static void checkError(const char *functionName)
{
GLenum error;
while (( error = glGetError() ) != GL_NO_ERROR)
{
fprintf (stderr, "GL error 0x%X detected in %s\n", error, functionName);
}
}
extern int gShapeIndex;
#include "GLInstanceRendererInternalData.h"
struct InternalDataRenderer : public GLInstanceRendererInternalData
{
b3Vector3 m_cameraPosition;
b3Vector3 m_cameraTargetPosition;
float m_cameraDistance;
b3Vector3 m_cameraUp;
float m_azi;
float m_ele;
float m_mouseXpos;
float m_mouseYpos;
bool m_mouseInitialized;
int m_mouseButton;
GLuint m_defaultTexturehandle;
InternalDataRenderer() :
m_cameraPosition(b3Vector3(0,0,0)),
m_cameraTargetPosition(b3Vector3(15,2,-24)),
m_cameraDistance(150),
m_cameraUp(0,1,0),
m_azi(100.f),//135.f),
//m_ele(25.f),
m_ele(25.f),
m_mouseInitialized(false),
m_mouseButton(0)
{
}
void wheelCallback( float deltax, float deltay)
{
if (!m_mouseButton)
{
if (b3Fabs(deltax)>b3Fabs(deltay))
{
m_azi -= deltax*0.1;
} else
{
m_cameraDistance -= deltay*0.1;
//b3Vector3 fwd = m_cameraTargetPosition-m_cameraPosition;
//fwd.normalize();
//m_cameraTargetPosition += fwd*deltay*0.1;
}
} else
{
if (b3Fabs(deltax)>b3Fabs(deltay))
{
b3Vector3 fwd = m_cameraTargetPosition-m_cameraPosition;
b3Vector3 side = m_cameraUp.cross(fwd);
side.normalize();
m_cameraTargetPosition += side * deltax*0.1;
} else
{
m_cameraTargetPosition -= m_cameraUp * deltay*0.1;
}
}
}
void mouseMoveCallback(float x, float y)
{
if (m_mouseButton)
{
float xDelta = x-m_mouseXpos;
float yDelta = y-m_mouseYpos;
// if (b3Fabs(xDelta)>b3Fabs(yDelta))
// {
m_azi += xDelta*0.1;
// } else
// {
m_ele += yDelta*0.1;
// }
}
m_mouseXpos = x;
m_mouseYpos = y;
m_mouseInitialized = true;
}
void mouseButtonCallback(int button, int state, float x, float y)
{
m_mouseButton=state;
m_mouseXpos = x;
m_mouseYpos = y;
m_mouseInitialized = true;
}
void keyboardCallback(unsigned char key, int x, int y)
{
printf("world\n");
}
};
struct GLInstanceRendererInternalData* GLInstancingRenderer::getInternalData()
{
return m_data;
}
void b3DefaultWheelCallback(float deltax, float deltay)
{
if (sData2)
sData2->wheelCallback(deltax,deltay);
}
void b3DefaultMouseButtonCallback(int button, int state, float x, float y)
{
if (sData2)
sData2->mouseButtonCallback(button, state, x, y);
}
void b3DefaultMouseMoveCallback( float x, float y)
{
if (sData2)
sData2->mouseMoveCallback( x, y);
}
void b3DefaultKeyboardCallback(int key, int state)
{
}
static GLuint instancingShader; // The instancing renderer
static GLuint instancingShaderPointSprite; // The point sprite instancing renderer
static bool done = false;
static GLint angle_loc = 0;
static GLint ModelViewMatrix=0;
static GLint ProjectionMatrix=0;
static GLint uniform_texture_diffuse = 0;
static GLint screenWidthPointSprite=0;
static GLint ModelViewMatrixPointSprite=0;
static GLint ProjectionMatrixPointSprite=0;
static GLint uniform_texture_diffusePointSprite= 0;
GLInstancingRenderer::GLInstancingRenderer(int maxNumObjectCapacity, int maxShapeCapacityInBytes)
:m_maxNumObjectCapacity(maxNumObjectCapacity),
m_maxShapeCapacityInBytes(maxShapeCapacityInBytes),
m_textureenabled(true),
m_textureinitialized(false)
{
m_data = new InternalDataRenderer;
sData2 = m_data;
m_data->m_instance_positions_ptr.resize(m_maxNumObjectCapacity*4);
m_data->m_instance_quaternion_ptr.resize(m_maxNumObjectCapacity*4);
m_data->m_instance_colors_ptr.resize(m_maxNumObjectCapacity*4);
m_data->m_instance_scale_ptr.resize(m_maxNumObjectCapacity*3);
}
GLInstancingRenderer::~GLInstancingRenderer()
{
for (int i=0;i<m_graphicsInstances.size();i++)
{
if (m_graphicsInstances[i]->m_index_vbo)
{
glDeleteBuffers(1,&m_graphicsInstances[i]->m_index_vbo);
}
if (m_graphicsInstances[i]->m_cube_vao)
{
glDeleteVertexArrays(1,&m_graphicsInstances[i]->m_cube_vao);
}
}
sData2=0;
if (m_data)
{
if (m_data->m_vbo)
glDeleteBuffers(1,&m_data->m_vbo);
}
delete m_data;
}
//used for dynamic loading from disk (default switched off)
//#define MAX_SHADER_LENGTH 8192
//static GLubyte shaderText[MAX_SHADER_LENGTH];
static const char* vertexShader= \
"#version 330\n"
"precision highp float;\n"
"\n"
"\n"
"\n"
"layout (location = 0) in vec4 position;\n"
"layout (location = 1) in vec4 instance_position;\n"
"layout (location = 2) in vec4 instance_quaternion;\n"
"layout (location = 3) in vec2 uvcoords;\n"
"layout (location = 4) in vec3 vertexnormal;\n"
"layout (location = 5) in vec4 instance_color;\n"
"layout (location = 6) in vec3 instance_scale;\n"
"\n"
"\n"
"uniform float angle = 0.0;\n"
"uniform mat4 ModelViewMatrix;\n"
"uniform mat4 ProjectionMatrix;\n"
"\n"
"out Fragment\n"
"{\n"
" vec4 color;\n"
"} fragment;\n"
"\n"
"out Vert\n"
"{\n"
" vec2 texcoord;\n"
"} vert;\n"
"\n"
"\n"
"vec4 quatMul ( in vec4 q1, in vec4 q2 )\n"
"{\n"
" vec3 im = q1.w * q2.xyz + q1.xyz * q2.w + cross ( q1.xyz, q2.xyz );\n"
" vec4 dt = q1 * q2;\n"
" float re = dot ( dt, vec4 ( -1.0, -1.0, -1.0, 1.0 ) );\n"
" return vec4 ( im, re );\n"
"}\n"
"\n"
"vec4 quatFromAxisAngle(vec4 axis, in float angle)\n"
"{\n"
" float cah = cos(angle*0.5);\n"
" float sah = sin(angle*0.5);\n"
" float d = inversesqrt(dot(axis,axis));\n"
" vec4 q = vec4(axis.x*sah*d,axis.y*sah*d,axis.z*sah*d,cah);\n"
" return q;\n"
"}\n"
"//\n"
"// vector rotation via quaternion\n"
"//\n"
"vec4 quatRotate3 ( in vec3 p, in vec4 q )\n"
"{\n"
" vec4 temp = quatMul ( q, vec4 ( p, 0.0 ) );\n"
" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n"
"}\n"
"vec4 quatRotate ( in vec4 p, in vec4 q )\n"
"{\n"
" vec4 temp = quatMul ( q, p );\n"
" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n"
"}\n"
"\n"
"out vec3 lightDir,normal,ambient;\n"
"\n"
"void main(void)\n"
"{\n"
" vec4 q = instance_quaternion;\n"
" ambient = vec3(0.3,.3,0.3);\n"
" \n"
" \n"
" vec4 local_normal = (quatRotate3( vertexnormal,q));\n"
" vec3 light_pos = vec3(-0.3,0.1,0.1);\n"
" normal = local_normal.xyz;\n"//normalize(ModelViewMatrix * local_normal).xyz;\n"
"\n"
" lightDir = normalize(light_pos);//gl_LightSource[0].position.xyz));\n"
"// lightDir = normalize(vec3(gl_LightSource[0].position));\n"
" \n"
" vec4 axis = vec4(1,1,1,0);\n"
" vec4 localcoord = quatRotate3( position.xyz*instance_scale,q);\n"
" vec4 vertexPos = ProjectionMatrix * ModelViewMatrix *(instance_position+localcoord);\n"
"\n"
" gl_Position = vertexPos;\n"
" \n"
" fragment.color = instance_color;\n"
" vert.texcoord = uvcoords;\n"
"}\n"
;
static const char* fragmentShader= \
"#version 330\n"
"precision highp float;\n"
"\n"
"in Fragment\n"
"{\n"
" vec4 color;\n"
"} fragment;\n"
"\n"
"in Vert\n"
"{\n"
" vec2 texcoord;\n"
"} vert;\n"
"\n"
"uniform sampler2D Diffuse;\n"
"\n"
"in vec3 lightDir,normal,ambient;\n"
"\n"
"out vec4 color;\n"
"\n"
"void main_textured(void)\n"
"{\n"
" color = fragment.color;//texture2D(Diffuse,vert.texcoord);//fragment.color;\n"
"}\n"
"\n"
"void main(void)\n"
"{\n"
" vec4 texel = fragment.color*texture(Diffuse,vert.texcoord);//fragment.color;\n"
" vec3 ct,cf;\n"
" float intensity,at,af;\n"
" intensity = max(dot(lightDir,normalize(normal)),0);\n"
" cf = intensity*vec3(1.0,1.0,1.0)+ambient;"
" af = 1.0;\n"
" \n"
" ct = texel.rgb;\n"
" at = texel.a;\n"
" \n"
" color = vec4(ct * cf, at * af); \n"
"}\n"
;
static const char* vertexShaderPointSprite= \
"#version 330\n"
"precision highp float;\n"
"\n"
"\n"
"\n"
"layout (location = 0) in vec4 position;\n"
"layout (location = 1) in vec4 instance_position;\n"
"layout (location = 3) in vec2 uvcoords;\n"
"layout (location = 4) in vec3 vertexnormal;\n"
"layout (location = 5) in vec4 instance_color;\n"
"layout (location = 6) in vec3 instance_scale;\n"
"\n"
"\n"
"uniform float screenWidth = 700.f;\n"
"uniform mat4 ModelViewMatrix;\n"
"uniform mat4 ProjectionMatrix;\n"
"\n"
"out Fragment\n"
"{\n"
" vec4 color;\n"
"} fragment;\n"
"\n"
"\n"
"\n"
"//\n"
"// vector rotation via quaternion\n"
"//\n"
"\n"
"out vec3 ambient;\n"
"\n"
"void main(void)\n"
"{\n"
" ambient = vec3(0.3,.3,0.3);\n"
" \n"
" \n"
" vec4 axis = vec4(1,1,1,0);\n"
" vec4 vertexPos = ProjectionMatrix * ModelViewMatrix *(instance_position);\n"
" vec3 posEye = vec3(ModelViewMatrix * vec4(instance_position.xyz, 1.0));\n"
" float dist = length(posEye);\n"
" float pointRadius = 1.f;\n"
" gl_PointSize = instance_scale.x * pointRadius * (screenWidth / dist);\n"
"\n"
" gl_Position = vertexPos;\n"
" \n"
" fragment.color = instance_color;\n"
"}\n"
;
static const char* fragmentShaderPointSprite= \
"#version 330\n"
"precision highp float;\n"
"\n"
"in Fragment\n"
"{\n"
" vec4 color;\n"
"} fragment;\n"
"\n"
"\n"
"in vec3 ambient;\n"
"\n"
"out vec4 color;\n"
"\n"
"void main_textured(void)\n"
"{\n"
" color = fragment.color;//texture2D(Diffuse,vert.texcoord);//fragment.color;\n"
"}\n"
"\n"
"void main(void)\n"
"{\n"
" vec3 N;\n"
" N.xy = gl_PointCoord.st*vec2(2.0, -2.0) + vec2(-1.0, 1.0);\n"
" float mag = dot(N.xy, N.xy);\n"
" if (mag > 1.0) discard; \n"
" vec4 texel = vec4(1,0,0,1);\n"//fragment.color*texture(Diffuse,vert.texcoord);//fragment.color;\n"
" vec3 ct;\n"
" float at,af;\n"
" af = 1.0;\n"
" \n"
" ct = texel.rgb;\n"
" at = texel.a;\n"
" \n"
" vec3 lightDir= vec3(1,0,0);\n"
" float diffuse = max(0.0, dot(lightDir, N));\n"
" color = vec4(ct * diffuse, at * af); \n"
"}\n"
;
void GLInstancingRenderer::writeSingleInstanceTransformToCPU(float* position, float* orientation, int srcIndex)
{
m_data->m_instance_positions_ptr[srcIndex*4+0]=position[0];
m_data->m_instance_positions_ptr[srcIndex*4+1]=position[1];
m_data->m_instance_positions_ptr[srcIndex*4+2]=position[2];
m_data->m_instance_positions_ptr[srcIndex*4+3]=1;
m_data->m_instance_quaternion_ptr[srcIndex*4+0]=orientation[0];
m_data->m_instance_quaternion_ptr[srcIndex*4+1]=orientation[1];
m_data->m_instance_quaternion_ptr[srcIndex*4+2]=orientation[2];
m_data->m_instance_quaternion_ptr[srcIndex*4+3]=orientation[3];
/* m_data->m_instance_colors_ptr[srcIndex*4+0]=color[0];
m_data->m_instance_colors_ptr[srcIndex*4+1]=color[1];
m_data->m_instance_colors_ptr[srcIndex*4+2]=color[2];
m_data->m_instance_colors_ptr[srcIndex*4+3]=color[3];
*/
}
void GLInstancingRenderer::writeSingleInstanceColorToCPU(float* color, int srcIndex)
{
m_data->m_instance_colors_ptr[srcIndex*4+0]=color[0];
m_data->m_instance_colors_ptr[srcIndex*4+1]=color[1];
m_data->m_instance_colors_ptr[srcIndex*4+2]=color[2];
m_data->m_instance_colors_ptr[srcIndex*4+3]=color[3];
}
void GLInstancingRenderer::writeSingleInstanceTransformToGPU(float* position, float* orientation, int objectIndex)
{
glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
glFlush();
char* orgBase = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE);
//b3GraphicsInstance* gfxObj = m_graphicsInstances[k];
int totalNumInstances= 0;
for (int k=0;k<m_graphicsInstances.size();k++)
{
b3GraphicsInstance* gfxObj = m_graphicsInstances[k];
totalNumInstances+=gfxObj->m_numGraphicsInstances;
}
int POSITION_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4);
char* base = orgBase;
float* positions = (float*)(base+m_maxShapeCapacityInBytes);
float* orientations = (float*)(base+m_maxShapeCapacityInBytes + POSITION_BUFFER_SIZE);
positions[objectIndex*4] = position[0];
positions[objectIndex*4+1] = position[1];
positions[objectIndex*4+2] = position[2];
positions[objectIndex*4+3] = position[3];
orientations [objectIndex*4] = orientation[0];
orientations [objectIndex*4+1] = orientation[1];
orientations [objectIndex*4+2] = orientation[2];
orientations [objectIndex*4+3] = orientation[3];
glUnmapBuffer( GL_ARRAY_BUFFER);
glFlush();
}
void GLInstancingRenderer::writeTransforms()
{
glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
glFlush();
char* orgBase = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE);
if (orgBase)
{
int totalNumInstances= 0;
for (int k=0;k<m_graphicsInstances.size();k++)
{
b3GraphicsInstance* gfxObj = m_graphicsInstances[k];
totalNumInstances+=gfxObj->m_numGraphicsInstances;
}
m_data->m_totalNumInstances = totalNumInstances;
for (int k=0;k<m_graphicsInstances.size();k++)
{
//int k=0;
b3GraphicsInstance* gfxObj = m_graphicsInstances[k];
int POSITION_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4);
int ORIENTATION_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4);
int COLOR_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4);
// int SCALE_BUFFER_SIZE = (totalNumInstances*sizeof(float)*3);
char* base = orgBase;
float* positions = (float*)(base+m_maxShapeCapacityInBytes);
float* orientations = (float*)(base+m_maxShapeCapacityInBytes + POSITION_BUFFER_SIZE);
float* colors= (float*)(base+m_maxShapeCapacityInBytes + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE);
float* scaling= (float*)(base+m_maxShapeCapacityInBytes + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE);
//static int offset=0;
//offset++;
for (int i=0;i<gfxObj->m_numGraphicsInstances;i++)
{
int srcIndex=i+gfxObj->m_instanceOffset;
positions[srcIndex*4] = m_data->m_instance_positions_ptr[srcIndex*4];
positions[srcIndex*4+1] = m_data->m_instance_positions_ptr[srcIndex*4+1];
positions[srcIndex*4+2] = m_data->m_instance_positions_ptr[srcIndex*4+2];
positions[srcIndex*4+3] = m_data->m_instance_positions_ptr[srcIndex*4+3];
orientations[srcIndex*4]=m_data->m_instance_quaternion_ptr[srcIndex*4];
orientations[srcIndex*4+1]=m_data->m_instance_quaternion_ptr[srcIndex*4+1];
orientations[srcIndex*4+2]=m_data->m_instance_quaternion_ptr[srcIndex*4+2];
orientations[srcIndex*4+3]=m_data->m_instance_quaternion_ptr[srcIndex*4+3];
colors[srcIndex*4]=m_data->m_instance_colors_ptr[srcIndex*4];
colors[srcIndex*4+1]=m_data->m_instance_colors_ptr[srcIndex*4+1];
colors[srcIndex*4+2]=m_data->m_instance_colors_ptr[srcIndex*4+2];
colors[srcIndex*4+3]=m_data->m_instance_colors_ptr[srcIndex*4+3];
scaling[srcIndex*3]=m_data->m_instance_scale_ptr[srcIndex*3];
scaling[srcIndex*3+1]=m_data->m_instance_scale_ptr[srcIndex*3+1];
scaling[srcIndex*3+2]=m_data->m_instance_scale_ptr[srcIndex*3+2];
}
}
} else
{
printf("ERROR glMapBuffer failed\n");
}
glUnmapBuffer( GL_ARRAY_BUFFER);
//if this glFinish is removed, the animation is not always working/blocks
//@todo: figure out why
glFlush();
glBindBuffer(GL_ARRAY_BUFFER, 0);//m_data->m_vbo);
GLint err = glGetError();
assert(err==GL_NO_ERROR);
}
int GLInstancingRenderer::registerGraphicsInstance(int shapeIndex, const float* position, const float* quaternion, const float* color, const float* scaling)
{
b3Assert(shapeIndex == (m_graphicsInstances.size()-1));
b3Assert(m_graphicsInstances.size()<m_maxNumObjectCapacity-1);
b3GraphicsInstance* gfxObj = m_graphicsInstances[shapeIndex];
int index = gfxObj->m_numGraphicsInstances + gfxObj->m_instanceOffset;
m_data->m_instance_positions_ptr[index*4]=position[0];
m_data->m_instance_positions_ptr[index*4+1]=position[1];
m_data->m_instance_positions_ptr[index*4+2]=position[2];
m_data->m_instance_positions_ptr[index*4+3]=1;
m_data->m_instance_quaternion_ptr[index*4]=quaternion[0];
m_data->m_instance_quaternion_ptr[index*4+1]=quaternion[1];
m_data->m_instance_quaternion_ptr[index*4+2]=quaternion[2];
m_data->m_instance_quaternion_ptr[index*4+3]=quaternion[3];
m_data->m_instance_colors_ptr[index*4]=color[0];
m_data->m_instance_colors_ptr[index*4+1]=color[1];
m_data->m_instance_colors_ptr[index*4+2]=color[2];
m_data->m_instance_colors_ptr[index*4+3]=color[3];
m_data->m_instance_scale_ptr[index*3] = scaling[0];
m_data->m_instance_scale_ptr[index*3+1] = scaling[1];
m_data->m_instance_scale_ptr[index*3+2] = scaling[2];
gfxObj->m_numGraphicsInstances++;
return gfxObj->m_numGraphicsInstances;
}
int GLInstancingRenderer::registerShape(const float* vertices, int numvertices, const int* indices, int numIndices,int primitiveType)
{
b3GraphicsInstance* gfxObj = new b3GraphicsInstance;
gfxObj->m_primitiveType = primitiveType;
if (m_graphicsInstances.size())
{
b3GraphicsInstance* prevObj = m_graphicsInstances[m_graphicsInstances.size()-1];
gfxObj->m_instanceOffset = prevObj->m_instanceOffset + prevObj->m_numGraphicsInstances;
gfxObj->m_vertexArrayOffset = prevObj->m_vertexArrayOffset + prevObj->m_numVertices;
} else
{
gfxObj->m_instanceOffset = 0;
}
m_graphicsInstances.push_back(gfxObj);
gfxObj->m_numIndices = numIndices;
gfxObj->m_numVertices = numvertices;
glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
char* dest= (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_WRITE_ONLY);//GL_WRITE_ONLY
int vertexStrideInBytes = 9*sizeof(float);
int sz = numvertices*vertexStrideInBytes;
memcpy(dest+vertexStrideInBytes*gfxObj->m_vertexArrayOffset,vertices,sz);
glUnmapBuffer( GL_ARRAY_BUFFER);
glGenBuffers(1, &gfxObj->m_index_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gfxObj->m_index_vbo);
int indexBufferSizeInBytes = gfxObj->m_numIndices*sizeof(int);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeInBytes, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,indexBufferSizeInBytes,indices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glGenVertexArrays(1, &gfxObj->m_cube_vao);
glBindVertexArray(gfxObj->m_cube_vao);
glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
return m_graphicsInstances.size()-1;
}
void GLInstancingRenderer::InitShaders()
{
int POSITION_BUFFER_SIZE = (m_maxNumObjectCapacity*sizeof(float)*4);
int ORIENTATION_BUFFER_SIZE = (m_maxNumObjectCapacity*sizeof(float)*4);
int COLOR_BUFFER_SIZE = (m_maxNumObjectCapacity*sizeof(float)*4);
int SCALE_BUFFER_SIZE = (m_maxNumObjectCapacity*sizeof(float)*3);
instancingShaderPointSprite = gltLoadShaderPair(vertexShaderPointSprite,fragmentShaderPointSprite);
glUseProgram(instancingShaderPointSprite);
ModelViewMatrixPointSprite = glGetUniformLocation(instancingShaderPointSprite, "ModelViewMatrix");
ProjectionMatrixPointSprite = glGetUniformLocation(instancingShaderPointSprite, "ProjectionMatrix");
screenWidthPointSprite = glGetUniformLocation(instancingShaderPointSprite, "screenWidth");
instancingShader = gltLoadShaderPair(vertexShader,fragmentShader);
glLinkProgram(instancingShader);
glUseProgram(instancingShader);
angle_loc = glGetUniformLocation(instancingShader, "angle");
ModelViewMatrix = glGetUniformLocation(instancingShader, "ModelViewMatrix");
ProjectionMatrix = glGetUniformLocation(instancingShader, "ProjectionMatrix");
uniform_texture_diffuse = glGetUniformLocation(instancingShader, "Diffuse");
glUseProgram(0);
//GLuint offset = 0;
glGenBuffers(1, &m_data->m_vbo);
checkError("glGenBuffers");
glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
int size = m_maxShapeCapacityInBytes + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE+SCALE_BUFFER_SIZE;
m_data->m_vboSize = size;
glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);//GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void GLInstancingRenderer::init()
{
GLint err = glGetError();
assert(err==GL_NO_ERROR);
err = glGetError();
assert(err==GL_NO_ERROR);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
err = glGetError();
assert(err==GL_NO_ERROR);
glClearColor(float(0.7),float(0.7),float(0.7),float(0));
err = glGetError();
assert(err==GL_NO_ERROR);
err = glGetError();
assert(err==GL_NO_ERROR);
{
B3_PROFILE("texture");
if(m_textureenabled)
{
if(!m_textureinitialized)
{
glActiveTexture(GL_TEXTURE0);
GLubyte* image=new GLubyte[256*256*3];
for(int y=0;y<256;++y)
{
// const int t=y>>5;
GLubyte* pi=image+y*256*3;
for(int x=0;x<256;++x)
{
if (x<2||y<2||x>253||y>253)
{
pi[0]=0;
pi[1]=0;
pi[2]=0;
} else
{
pi[0]=255;
pi[1]=255;
pi[2]=255;
}
/*
const int s=x>>5;
const GLubyte b=180;
GLubyte c=b+((s+t&1)&1)*(255-b);
pi[0]=c;
pi[1]=c;
pi[2]=c;
*/
pi+=3;
}
}
glGenTextures(1,(GLuint*)&m_data->m_defaultTexturehandle);
glBindTexture(GL_TEXTURE_2D,m_data->m_defaultTexturehandle);
err = glGetError();
assert(err==GL_NO_ERROR);
#if 0
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
err = glGetError();
assert(err==GL_NO_ERROR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
err = glGetError();
assert(err==GL_NO_ERROR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
err = glGetError();
assert(err==GL_NO_ERROR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
err = glGetError();
assert(err==GL_NO_ERROR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
err = glGetError();
assert(err==GL_NO_ERROR);
#endif
err = glGetError();
assert(err==GL_NO_ERROR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256,256,0,GL_RGB,GL_UNSIGNED_BYTE,image);
glGenerateMipmap(GL_TEXTURE_2D);
err = glGetError();
assert(err==GL_NO_ERROR);
delete[] image;
m_textureinitialized=true;
}
err = glGetError();
assert(err==GL_NO_ERROR);
glBindTexture(GL_TEXTURE_2D,m_data->m_defaultTexturehandle);
err = glGetError();
assert(err==GL_NO_ERROR);
} else
{
glDisable(GL_TEXTURE_2D);
err = glGetError();
assert(err==GL_NO_ERROR);
}
}
//glEnable(GL_COLOR_MATERIAL);
err = glGetError();
assert(err==GL_NO_ERROR);
// glEnable(GL_CULL_FACE);
// glCullFace(GL_BACK);
}
void b3CreateFrustum(
float left,
float right,
float bottom,
float top,
float nearVal,
float farVal,
float frustum[16])
{
frustum[0*4+0] = (float(2) * nearVal) / (right - left);
frustum[0*4+1] = float(0);
frustum[0*4+2] = float(0);
frustum[0*4+3] = float(0);
frustum[1*4+0] = float(0);
frustum[1*4+1] = (float(2) * nearVal) / (top - bottom);
frustum[1*4+2] = float(0);
frustum[1*4+3] = float(0);
frustum[2*4+0] = (right + left) / (right - left);
frustum[2*4+1] = (top + bottom) / (top - bottom);
frustum[2*4+2] = -(farVal + nearVal) / (farVal - nearVal);
frustum[2*4+3] = float(-1);
frustum[3*4+0] = float(0);
frustum[3*4+1] = float(0);
frustum[3*4+2] = -(float(2) * farVal * nearVal) / (farVal - nearVal);
frustum[3*4+3] = float(0);
}
void b3CreateLookAt(const b3Vector3& eye, const b3Vector3& center,const b3Vector3& up, GLfloat result[16])
{
b3Vector3 f = (center - eye).normalized();
b3Vector3 u = up.normalized();
b3Vector3 s = (f.cross(u)).normalized();
u = s.cross(f);
result[0*4+0] = s.getX();
result[1*4+0] = s.getY();
result[2*4+0] = s.getZ();
result[0*4+1] = u.getX();
result[1*4+1] = u.getY();
result[2*4+1] = u.getZ();
result[0*4+2] =-f.getX();
result[1*4+2] =-f.getY();
result[2*4+2] =-f.getZ();
result[3*4+0] = -s.dot(eye);
result[3*4+1] = -u.dot(eye);
result[3*4+2] = f.dot(eye);
result[3*4+3] = 1.f;
}
void GLInstancingRenderer::resize(int width, int height)
{
m_glutScreenWidth = width;
m_glutScreenHeight = height;
}
void GLInstancingRenderer::updateCamera()
{
GLint err = glGetError();
assert(err==GL_NO_ERROR);
int m_forwardAxis(2);
float m_frustumZNear=1;
float m_frustumZFar=10000.f;
// m_azi=m_azi+0.01;
b3Scalar rele = m_data->m_ele * b3Scalar(0.01745329251994329547);// rads per deg
b3Scalar razi = m_data->m_azi * b3Scalar(0.01745329251994329547);// rads per deg
b3Quaternion rot(m_data->m_cameraUp,razi);
b3Vector3 eyePos(0,0,0);
eyePos[m_forwardAxis] = -m_data->m_cameraDistance;
b3Vector3 forward(eyePos[0],eyePos[1],eyePos[2]);
if (forward.length2() < SIMD_EPSILON)
{
forward.setValue(1.f,0.f,0.f);
}
b3Vector3 right = m_data->m_cameraUp.cross(forward);
b3Quaternion roll(right,-rele);
eyePos = b3Matrix3x3(rot) * b3Matrix3x3(roll) * eyePos;
m_data->m_cameraPosition[0] = eyePos.getX();
m_data->m_cameraPosition[1] = eyePos.getY();
m_data->m_cameraPosition[2] = eyePos.getZ();
m_data->m_cameraPosition += m_data->m_cameraTargetPosition;
if (m_glutScreenWidth == 0 && m_glutScreenHeight == 0)
return;
b3Scalar aspect;
b3Vector3 extents;
aspect = m_glutScreenWidth / (b3Scalar)m_glutScreenHeight;
extents.setValue(aspect * 1.0f, 1.0f,0);
if (m_ortho)
{
// reset matrix
extents *= m_data->m_cameraDistance;
//b3Vector3 lower = m_data->m_cameraTargetPosition - extents;
//b3Vector3 upper = m_data->m_cameraTargetPosition + extents;
//gluOrtho2D(lower.x, upper.x, lower.y, upper.y);
//glTranslatef(100,210,0);
} else
{
// glFrustum (-aspect, aspect, -1.0, 1.0, 1.0, 10000.0);
}
if (m_glutScreenWidth > m_glutScreenHeight)
{
b3CreateFrustum(-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar,projectionMatrix);
} else
{
b3CreateFrustum(-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar,projectionMatrix);
}
b3CreateLookAt(m_data->m_cameraPosition,m_data->m_cameraTargetPosition,m_data->m_cameraUp,modelviewMatrix);
}
void GLInstancingRenderer::getCameraPosition(float cameraPos[4])
{
cameraPos[0] = m_data->m_cameraPosition[0];
cameraPos[1] = m_data->m_cameraPosition[1];
cameraPos[2] = m_data->m_cameraPosition[2];
cameraPos[3] = 1.f;
}
void GLInstancingRenderer::setCameraDistance(float dist)
{
m_data->m_cameraDistance = dist;
}
void GLInstancingRenderer::setCameraYaw(float yaw)
{
m_data->m_ele = yaw;
}
void GLInstancingRenderer::setCameraPitch(float pitch)
{
m_data->m_azi = pitch;
}
void GLInstancingRenderer::setCameraTargetPosition(float cameraPos[4])
{
m_data->m_cameraTargetPosition = b3Vector3(cameraPos[0],cameraPos[1],cameraPos[2]);
}
void GLInstancingRenderer::getCameraTargetPosition(float cameraPos[4]) const
{
cameraPos[0] = m_data->m_cameraTargetPosition.getX();
cameraPos[1] = m_data->m_cameraTargetPosition.getY();
cameraPos[2] = m_data->m_cameraTargetPosition.getZ();
}
float GLInstancingRenderer::getCameraDistance() const
{
return m_data->m_cameraDistance;
}
void GLInstancingRenderer::getMouseDirection(float* dir, int x, int y)
{
float top = 1.f;
float bottom = -1.f;
float nearPlane = 1.f;
float tanFov = (top-bottom)*0.5f / nearPlane;
float fov = b3Scalar(2.0) * b3Atan(tanFov);
b3Vector3 rayFrom = m_data->m_cameraPosition;
b3Vector3 rayForward = (m_data->m_cameraTargetPosition-m_data->m_cameraPosition);
rayForward.normalize();
float farPlane = 10000.f;
rayForward*= farPlane;
b3Vector3 rightOffset;
b3Vector3 vertical = m_data->m_cameraUp;
b3Vector3 hor;
hor = rayForward.cross(vertical);
hor.normalize();
vertical = hor.cross(rayForward);
vertical.normalize();
float tanfov = tanf(0.5f*fov);
hor *= 2.f * farPlane * tanfov;
vertical *= 2.f * farPlane * tanfov;
b3Scalar aspect;
aspect = m_glutScreenWidth / (b3Scalar)m_glutScreenHeight;
hor*=aspect;
b3Vector3 rayToCenter = rayFrom + rayForward;
b3Vector3 dHor = hor * 1.f/float(m_glutScreenWidth);
b3Vector3 dVert = vertical * 1.f/float(m_glutScreenHeight);
b3Vector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical;
rayTo += b3Scalar(x) * dHor;
rayTo -= b3Scalar(y) * dVert;
dir[0] = rayTo[0];
dir[1] = rayTo[1];
dir[2] = rayTo[2];
}
void GLInstancingRenderer::RenderScene(void)
{
B3_PROFILE("GLInstancingRenderer::RenderScene");
{
B3_PROFILE("init");
init();
}
GLint err = glGetError();
assert(err==GL_NO_ERROR);
{
B3_PROFILE("updateCamera");
updateCamera();
}
err = glGetError();
assert(err==GL_NO_ERROR);
//render coordinate system
#if 0
glBegin(GL_LINES);
err = glGetError();
assert(err==GL_NO_ERROR);
glColor3f(1,0,0);
glVertex3f(0,0,0);
glVertex3f(1,0,0);
glColor3f(0,1,0);
glVertex3f(0,0,0);
glVertex3f(0,1,0);
glColor3f(0,0,1);
glVertex3f(0,0,0);
glVertex3f(0,0,1);
glEnd();
#endif
//do a finish, to make sure timings are clean
// glFinish();
// glBindBuffer(GL_ARRAY_BUFFER, 0);
{
B3_PROFILE("glFlush2");
glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
glFlush();
}
err = glGetError();
assert(err==GL_NO_ERROR);
//updatePos();
// simulationLoop();
//useCPU = true;
int totalNumInstances = 0;
for (int i=0;i<m_graphicsInstances.size();i++)
{
totalNumInstances+=m_graphicsInstances[i]->m_numGraphicsInstances;
}
int curOffset = 0;
for (int i=0;i<m_graphicsInstances.size();i++)
{
b3GraphicsInstance* gfxObj = m_graphicsInstances[i];
if (gfxObj->m_numGraphicsInstances)
{
// int myOffset = gfxObj->m_instanceOffset*4*sizeof(float);
int POSITION_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4);
int ORIENTATION_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4);
int COLOR_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4);
// int SCALE_BUFFER_SIZE = (totalNumInstances*sizeof(float)*3);
glBindVertexArray(gfxObj->m_cube_vao);
int vertexStride = 9*sizeof(float);
int vertexBase = gfxObj->m_vertexArrayOffset*vertexStride;
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid*)vertexBase);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+m_maxShapeCapacityInBytes));
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+m_maxShapeCapacityInBytes+POSITION_BUFFER_SIZE));
int uvoffset = 7*sizeof(float)+vertexBase;
int normaloffset = 4*sizeof(float)+vertexBase;
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)uvoffset);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)normaloffset);
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+m_maxShapeCapacityInBytes+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE));
glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*3*sizeof(float)+m_maxShapeCapacityInBytes+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
glEnableVertexAttribArray(6);
glVertexAttribDivisorARB(0, 0);
glVertexAttribDivisorARB(1, 1);
glVertexAttribDivisorARB(2, 1);
glVertexAttribDivisorARB(3, 0);
glVertexAttribDivisorARB(4, 0);
glVertexAttribDivisorARB(5, 1);
glVertexAttribDivisorARB(6, 1);
{
B3_PROFILE("glFlush");
glFlush();
}
int indexCount = gfxObj->m_numIndices;
int indexOffset = 0;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gfxObj->m_index_vbo);
{
B3_PROFILE("glDrawElementsInstanced");
if (gfxObj->m_primitiveType==B3_GL_POINTS)
{
glUseProgram(instancingShaderPointSprite);
glUniformMatrix4fv(ProjectionMatrixPointSprite, 1, false, &projectionMatrix[0]);
glUniformMatrix4fv(ModelViewMatrixPointSprite, 1, false, &modelviewMatrix[0]);
glUniform1f(screenWidthPointSprite,m_glutScreenWidth);
//glUniform1i(uniform_texture_diffusePointSprite, 0);
err = glGetError();
assert(err==GL_NO_ERROR);
glPointSize(20);
#ifndef __APPLE__
glEnable(GL_POINT_SPRITE_ARB);
glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
#endif
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glDrawElementsInstanced(GL_POINTS, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances);
} else
{
glUseProgram(instancingShader);
glUniform1f(angle_loc, 0);
glUniformMatrix4fv(ProjectionMatrix, 1, false, &projectionMatrix[0]);
glUniformMatrix4fv(ModelViewMatrix, 1, false, &modelviewMatrix[0]);
glUniform1i(uniform_texture_diffuse, 0);
glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances);
}
//glDrawElementsInstanced(GL_LINE_LOOP, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances);
}
}
curOffset+= gfxObj->m_numGraphicsInstances;
}
err = glGetError();
assert(err==GL_NO_ERROR);
{
B3_PROFILE("glUseProgram(0);");
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
}
err = glGetError();
assert(err==GL_NO_ERROR);
}
void GLInstancingRenderer::CleanupShaders()
{
}