BGE: Some as of yet unmerged work I did in the Swiss branch. These changes include:

* Cleaning up the conversion code to avoid a per-face material conversion. Materials are now stored in buckets and only converted if a new material is found. This replaces some of Campbell's earlier work on the subject. His work wasn't as thorough, but it was much safer for a release.
  * Shaders are only compiled for LibLoaded materials once. Before they could be compiled twice, which could really slow things down.
  * Refactoring the rasterizer code to use a strategy design pattern to handle different geometry rendering methods such as immediate mode, vertex arrays and vertex buffer objects. VBOs are added, but they will be disabled in a following commit since they are still slower than vertex arrays with display lists. However, VBOs are still useful for mobile, so it's good to keep them around.
  * Better multi-uv support. The BGE should now be able to handle more than two UV layers, which should help it better match the viewport.
This commit is contained in:
Mitchell Stokes
2012-12-18 20:56:25 +00:00
parent 6b2af22d37
commit ef0473994b
46 changed files with 1867 additions and 1296 deletions

View File

@@ -43,6 +43,10 @@
#include "MT_CmMatrix4x4.h"
#include "RAS_IRenderTools.h" // rendering text
#include "RAS_StorageIM.h"
#include "RAS_StorageVA.h"
#include "RAS_StorageVBO.h"
#include "GPU_draw.h"
#include "GPU_material.h"
#include "GPU_extensions.h"
@@ -74,7 +78,7 @@ static GLuint right_eye_vinterlace_mask[32];
*/
static GLuint hinterlace_mask[33];
RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas)
RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, int storage)
:RAS_IRasterizer(canvas),
m_2DCanvas(canvas),
m_fogenabled(false),
@@ -93,7 +97,8 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas)
m_attrib_num(0),
//m_last_alphablend(GPU_BLEND_SOLID),
m_last_frontface(true),
m_materialCachingInfo(0)
m_materialCachingInfo(0),
m_storage_type(storage)
{
m_viewmatrix.setIdentity();
m_viewinvmatrix.setIdentity();
@@ -107,6 +112,24 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas)
hinterlace_mask[32] = 0;
m_prevafvalue = GPU_get_anisotropic();
if (m_storage_type == RAS_VBO /*|| m_storage_type == RAS_AUTO_STORAGE && GLEW_ARB_vertex_buffer_object*/)
{
m_storage = new RAS_StorageVBO(&m_texco_num, m_texco, &m_attrib_num, m_attrib);
m_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib);
m_storage_type = RAS_VBO;
}
else if (m_storage_type == RAS_VA || m_storage_type == RAS_AUTO_STORAGE && GLEW_VERSION_1_1)
{
m_storage = new RAS_StorageVA(&m_texco_num, m_texco, &m_attrib_num, m_attrib);
m_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib);
m_storage_type = RAS_VA;
}
else
{
m_storage = m_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib);
m_storage_type = RAS_IMMEDIATE;
}
}
@@ -115,10 +138,16 @@ RAS_OpenGLRasterizer::~RAS_OpenGLRasterizer()
{
// Restore the previous AF value
GPU_set_anisotropic(m_prevafvalue);
if (m_failsafe_storage && m_failsafe_storage != m_storage)
delete m_failsafe_storage;
if (m_storage)
delete m_storage;
}
bool RAS_OpenGLRasterizer::Init()
{
bool storage_init;
GPU_state_init();
@@ -146,7 +175,9 @@ bool RAS_OpenGLRasterizer::Init()
glShadeModel(GL_SMOOTH);
return true;
storage_init = m_storage->Init();
return true && storage_init;
}
@@ -267,6 +298,8 @@ bool RAS_OpenGLRasterizer::SetMaterial(const RAS_IPolyMaterial& mat)
void RAS_OpenGLRasterizer::Exit()
{
m_storage->Exit();
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glClearDepth(1.0);
@@ -289,7 +322,7 @@ void RAS_OpenGLRasterizer::Exit()
bool RAS_OpenGLRasterizer::BeginFrame(int drawingmode, double time)
{
m_time = time;
m_drawingmode = drawingmode;
SetDrawingMode(drawingmode);
// Blender camera routine destroys the settings
if (m_drawingmode < KX_SOLID)
@@ -328,6 +361,8 @@ void RAS_OpenGLRasterizer::SetDrawingMode(int drawingmode)
if (m_drawingmode == KX_WIREFRAME)
glDisable(GL_CULL_FACE);
m_storage->SetDrawingMode(drawingmode);
}
int RAS_OpenGLRasterizer::GetDrawingMode()
@@ -666,7 +701,7 @@ void RAS_OpenGLRasterizer::IndexPrimitives_3DText(RAS_MeshSlot& ms,
glattrib = -1;
if (GLEW_ARB_vertex_program)
for (unit=0; unit<m_attrib_num; unit++)
if (m_attrib[unit] == RAS_TEXCO_UV1)
if (m_attrib[unit] == RAS_TEXCO_UV)
glattrib = unit;
rendertools->RenderText(polymat->GetDrawingMode(), polymat,
@@ -708,257 +743,20 @@ void RAS_OpenGLRasterizer::SetAttrib(TexCoGen coords, int unit)
m_attrib[unit] = coords;
}
void RAS_OpenGLRasterizer::TexCoord(const RAS_TexVert &tv)
{
int unit;
if (GLEW_ARB_multitexture) {
for (unit=0; unit<m_texco_num; unit++) {
if (tv.getFlag() & RAS_TexVert::SECOND_UV && (int)tv.getUnit() == unit) {
glMultiTexCoord2fvARB(GL_TEXTURE0_ARB+unit, tv.getUV2());
continue;
}
switch (m_texco[unit]) {
case RAS_TEXCO_ORCO:
case RAS_TEXCO_GLOB:
glMultiTexCoord3fvARB(GL_TEXTURE0_ARB+unit, tv.getXYZ());
break;
case RAS_TEXCO_UV1:
glMultiTexCoord2fvARB(GL_TEXTURE0_ARB+unit, tv.getUV1());
break;
case RAS_TEXCO_NORM:
glMultiTexCoord3fvARB(GL_TEXTURE0_ARB+unit, tv.getNormal());
break;
case RAS_TEXTANGENT:
glMultiTexCoord4fvARB(GL_TEXTURE0_ARB+unit, tv.getTangent());
break;
case RAS_TEXCO_UV2:
glMultiTexCoord2fvARB(GL_TEXTURE0_ARB+unit, tv.getUV2());
break;
default:
break;
}
}
}
if (GLEW_ARB_vertex_program) {
for (unit=0; unit<m_attrib_num; unit++) {
switch (m_attrib[unit]) {
case RAS_TEXCO_ORCO:
case RAS_TEXCO_GLOB:
glVertexAttrib3fvARB(unit, tv.getXYZ());
break;
case RAS_TEXCO_UV1:
glVertexAttrib2fvARB(unit, tv.getUV1());
break;
case RAS_TEXCO_NORM:
glVertexAttrib3fvARB(unit, tv.getNormal());
break;
case RAS_TEXTANGENT:
glVertexAttrib4fvARB(unit, tv.getTangent());
break;
case RAS_TEXCO_UV2:
glVertexAttrib2fvARB(unit, tv.getUV2());
break;
case RAS_TEXCO_VCOL:
glVertexAttrib4ubvARB(unit, tv.getRGBA());
break;
default:
break;
}
}
}
}
void RAS_OpenGLRasterizer::IndexPrimitives(RAS_MeshSlot& ms)
{
IndexPrimitivesInternal(ms, false);
if (ms.m_pDerivedMesh)
m_failsafe_storage->IndexPrimitives(ms);
else
m_storage->IndexPrimitives(ms);
}
void RAS_OpenGLRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms)
{
IndexPrimitivesInternal(ms, true);
}
static bool current_wireframe;
static RAS_MaterialBucket *current_bucket;
static RAS_IPolyMaterial *current_polymat;
static RAS_MeshSlot *current_ms;
static RAS_MeshObject *current_mesh;
static int current_blmat_nr;
static GPUVertexAttribs current_gpu_attribs;
static Image *current_image;
static int CheckMaterialDM(int matnr, void *attribs)
{
// only draw the current material
if (matnr != current_blmat_nr)
return 0;
GPUVertexAttribs *gattribs = (GPUVertexAttribs *)attribs;
if (gattribs)
memcpy(gattribs, &current_gpu_attribs, sizeof(GPUVertexAttribs));
return 1;
}
/*
static int CheckTexfaceDM(void *mcol, int index)
{
// index is the original face index, retrieve the polygon
RAS_Polygon* polygon = (index >= 0 && index < current_mesh->NumPolygons()) ?
current_mesh->GetPolygon(index) : NULL;
if (polygon && polygon->GetMaterial() == current_bucket) {
// must handle color.
if (current_wireframe)
return 2;
if (current_ms->m_bObjectColor) {
MT_Vector4& rgba = current_ms->m_RGBAcolor;
glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
// don't use mcol
return 2;
}
if (!mcol) {
// we have to set the color from the material
unsigned char rgba[4];
current_polymat->GetMaterialRGBAColor(rgba);
glColor4ubv((const GLubyte *)rgba);
return 2;
}
return 1;
}
return 0;
}
*/
static DMDrawOption CheckTexDM(MTFace *tface, int has_mcol, int matnr)
{
// index is the original face index, retrieve the polygon
if (matnr == current_blmat_nr &&
(tface == NULL || tface->tpage == current_image)) {
// must handle color.
if (current_wireframe)
return DM_DRAW_OPTION_NO_MCOL;
if (current_ms->m_bObjectColor) {
MT_Vector4& rgba = current_ms->m_RGBAcolor;
glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
// don't use mcol
return DM_DRAW_OPTION_NO_MCOL;
}
if (!has_mcol) {
// we have to set the color from the material
unsigned char rgba[4];
current_polymat->GetMaterialRGBAColor(rgba);
glColor4ubv((const GLubyte *)rgba);
return DM_DRAW_OPTION_NO_MCOL;
}
return DM_DRAW_OPTION_NORMAL;
}
return DM_DRAW_OPTION_SKIP;
}
void RAS_OpenGLRasterizer::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi)
{
bool obcolor = ms.m_bObjectColor;
bool wireframe = m_drawingmode <= KX_WIREFRAME;
MT_Vector4& rgba = ms.m_RGBAcolor;
RAS_MeshSlot::iterator it;
if (ms.m_pDerivedMesh) {
// mesh data is in derived mesh,
current_bucket = ms.m_bucket;
current_polymat = current_bucket->GetPolyMaterial();
current_ms = &ms;
current_mesh = ms.m_mesh;
current_wireframe = wireframe;
// MCol *mcol = (MCol*)ms.m_pDerivedMesh->getFaceDataArray(ms.m_pDerivedMesh, CD_MCOL); /* UNUSED */
// handle two-side
if (current_polymat->GetDrawingMode() & RAS_IRasterizer::KX_BACKCULL)
this->SetCullFace(true);
else
this->SetCullFace(false);
if (current_polymat->GetFlag() & RAS_BLENDERGLSL) {
// GetMaterialIndex return the original mface material index,
// increment by 1 to match what derived mesh is doing
current_blmat_nr = current_polymat->GetMaterialIndex()+1;
// For GLSL we need to retrieve the GPU material attribute
Material* blmat = current_polymat->GetBlenderMaterial();
Scene* blscene = current_polymat->GetBlenderScene();
if (!wireframe && blscene && blmat)
GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat), &current_gpu_attribs);
else
memset(&current_gpu_attribs, 0, sizeof(current_gpu_attribs));
// DM draw can mess up blending mode, restore at the end
int current_blend_mode = GPU_get_material_alpha_blend();
ms.m_pDerivedMesh->drawFacesGLSL(ms.m_pDerivedMesh, CheckMaterialDM);
GPU_set_material_alpha_blend(current_blend_mode);
}
else {
//ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol);
current_blmat_nr = current_polymat->GetMaterialIndex();
current_image = current_polymat->GetBlenderImage();
ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL);
}
return;
}
// iterate over display arrays, each containing an index + vertex array
for (ms.begin(it); !ms.end(it); ms.next(it)) {
RAS_TexVert *vertex;
size_t i, j, numvert;
numvert = it.array->m_type;
if (it.array->m_type == RAS_DisplayArray::LINE) {
// line drawing
glBegin(GL_LINES);
for (i=0; i<it.totindex; i+=2)
{
vertex = &it.vertex[it.index[i]];
glVertex3fv(vertex->getXYZ());
vertex = &it.vertex[it.index[i+1]];
glVertex3fv(vertex->getXYZ());
}
glEnd();
}
else {
// triangle and quad drawing
if (it.array->m_type == RAS_DisplayArray::TRIANGLE)
glBegin(GL_TRIANGLES);
else
glBegin(GL_QUADS);
for (i=0; i<it.totindex; i+=numvert)
{
if (obcolor)
glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
for (j=0; j<numvert; j++) {
vertex = &it.vertex[it.index[i+j]];
if (!wireframe) {
if (!obcolor)
glColor4ubv((const GLubyte *)(vertex->getRGBA()));
glNormal3fv(vertex->getNormal());
if (multi)
TexCoord(*vertex);
else
glTexCoord2fv(vertex->getUV1());
}
glVertex3fv(vertex->getXYZ());
}
}
glEnd();
}
}
if (ms.m_pDerivedMesh)
m_failsafe_storage->IndexPrimitivesMulti(ms);
else
m_storage->IndexPrimitivesMulti(ms);
}
void RAS_OpenGLRasterizer::SetProjectionMatrix(MT_CmMatrix4x4 &mat)