Display optimizations part 1.

This patch changes the way we draw meshes by introducing
indexed drawing. This makes it possible to easily
upload and rearrange faces ad lib according to any criteria.

Currently we use material sorting but textured sorting and
hiding will be added to optimize textured drawing and skip
per face testing.

It also adds support for vertex buffers for subsurf
modifiers (Except from GLSL drawing), making drawing of
subsurf much faster without need for bogus modifiers.

Tests show that we gain approximately 20-25% performance
by that for solid mode drawing with up to 50% gains for
material drawing. Textured drawing should also have a
small performance gain, but more substantial optimizations
are possible there.

Reviewers: campbellbarton

Differential Revision: https://developer.blender.org/D1406
This commit is contained in:
Antonis Ryakiotakis 2015-07-14 16:48:23 +02:00
parent 1b8b9063f8
commit 107e34407d
Notes: blender-bot 2023-02-14 08:13:39 +01:00
Referenced by issue #47389, Weight paint + texture shows entirely transparent
7 changed files with 1639 additions and 1184 deletions

View File

@ -463,6 +463,9 @@ struct DerivedMesh {
void (*setMaterial)(void *userData, int matnr, void *attribs),
bool (*setFace)(void *userData, int index), void *userData);
struct GPUDrawObject *(*gpuObjectNew)(DerivedMesh *dm);
void (*copy_gpu_data)(DerivedMesh *dm, int type, float *varray, int *mat_orig_to_new, void *user_data);
/** Release reference to the DerivedMesh. This function decides internally
* if the DerivedMesh will be freed, or cached for later use. */
void (*release)(DerivedMesh *dm);

View File

@ -112,7 +112,7 @@ void BKE_pbvh_raycast_project_ray_root(
void BKE_pbvh_node_draw(PBVHNode *node, void *data);
void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
int (*setMaterial)(int matnr, void *attribs), bool wireframe);
int (*setMaterial)(int matnr, void *attribs), bool wireframe, bool fast);
/* PBVH Access */
typedef enum {

File diff suppressed because it is too large Load Diff

View File

@ -1679,6 +1679,7 @@ void BKE_pbvh_raycast_project_ray_root(
typedef struct {
DMSetMaterial setMaterial;
bool wireframe;
bool fast;
} PBVHNodeDrawData;
void BKE_pbvh_node_draw(PBVHNode *node, void *data_v)
@ -1705,7 +1706,8 @@ void BKE_pbvh_node_draw(PBVHNode *node, void *data_v)
if (!(node->flag & PBVH_FullyHidden)) {
GPU_draw_pbvh_buffers(node->draw_buffers,
data->setMaterial,
data->wireframe);
data->wireframe,
data->fast);
}
}
@ -1775,9 +1777,9 @@ static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node)
}
void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
DMSetMaterial setMaterial, bool wireframe)
DMSetMaterial setMaterial, bool wireframe, bool fast)
{
PBVHNodeDrawData draw_data = {setMaterial, wireframe};
PBVHNodeDrawData draw_data = {setMaterial, wireframe, fast};
PBVHNode **nodes;
int a, totnode;

View File

@ -72,6 +72,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_buffers.h"
#include "CCGSubSurf.h"
@ -1734,12 +1735,25 @@ static void ccgDM_drawLooseEdges(DerivedMesh *dm)
}
}
static void ccgDM_NormalFast(float *a, float *b, float *c, float *d, float no[3])
{
float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
no[0] = b_dY * a_cZ - b_dZ * a_cY;
no[1] = b_dZ * a_cX - b_dX * a_cZ;
no[2] = b_dX * a_cY - b_dY * a_cX;
normalize_v3(no);
}
static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
{
float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
float no[3];
no[0] = b_dY * a_cZ - b_dZ * a_cY;
no[1] = b_dZ * a_cX - b_dX * a_cZ;
no[2] = b_dX * a_cY - b_dY * a_cX;
@ -1749,46 +1763,35 @@ static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
}
/* Only used by non-editmesh types */
static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], bool fast, DMSetMaterial setMaterial)
static void ccgDM_buffer_copy_normal(DerivedMesh *dm, float *varray_,
int *UNUSED(mat_orig_to_new), void *UNUSED(user_data))
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
short *varray = (short *)varray_;
short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int step = (fast) ? gridSize - 1 : 1;
int i, totface = ccgSubSurf_getNumFaces(ss);
int drawcurrent = 0, matnr = -1, shademodel = -1;
int shademodel;
int start = 0;
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
if (ccgdm->pbvh && ccgdm->multires.mmd && !fast) {
if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
setMaterial, false);
glShadeModel(GL_FLAT);
}
return;
}
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
int new_matnr, new_shademodel;
short (*ln)[4][3] = NULL;
if (faceFlags) {
new_shademodel = (lnors || (faceFlags[index].flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT;
new_matnr = faceFlags[index].mat_nr;
shademodel = (lnors || (faceFlags[index].flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT;
}
else {
new_shademodel = GL_SMOOTH;
new_matnr = 0;
shademodel = GL_SMOOTH;
}
if (lnors) {
@ -1796,85 +1799,468 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
lnors += gridFaces * gridFaces * numVerts;
}
if (shademodel != new_shademodel || matnr != new_matnr) {
matnr = new_matnr;
shademodel = new_shademodel;
if (setMaterial)
drawcurrent = setMaterial(matnr + 1, NULL);
else
drawcurrent = 1;
glShadeModel(shademodel);
}
if (!drawcurrent)
continue;
for (S = 0; S < numVerts; S++) {
CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
if (ln) {
/* Can't use quad strips here... */
glBegin(GL_QUADS);
for (y = 0; y < gridFaces; y += step) {
for (x = 0; x < gridFaces; x += step) {
float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
float *b = CCG_grid_elem_co(&key, faceGridData, x + step, y + 0);
float *c = CCG_grid_elem_co(&key, faceGridData, x + step, y + step);
float *d = CCG_grid_elem_co(&key, faceGridData, x, y + step);
for (y = 0; y < gridFaces; y ++) {
for (x = 0; x < gridFaces; x ++) {
copy_v3_v3_short(&varray[start], ln[0][0]);
copy_v3_v3_short(&varray[start + 4], ln[0][3]);
copy_v3_v3_short(&varray[start + 8], ln[0][2]);
copy_v3_v3_short(&varray[start + 12], ln[0][1]);
glNormal3sv(ln[0][1]);
glVertex3fv(d);
glNormal3sv(ln[0][2]);
glVertex3fv(c);
glNormal3sv(ln[0][3]);
glVertex3fv(b);
glNormal3sv(ln[0][0]);
glVertex3fv(a);
ln += step;
start += 16;
ln ++;
}
}
glEnd();
}
else if (shademodel == GL_SMOOTH) {
for (y = 0; y < gridFaces; y += step) {
glBegin(GL_QUAD_STRIP);
for (x = 0; x < gridSize; x += step) {
CCGElem *a = CCG_grid_elem(&key, faceGridData, x, y + 0);
CCGElem *b = CCG_grid_elem(&key, faceGridData, x, y + step);
for (y = 0; y < gridFaces; y ++) {
for (x = 0; x < gridFaces; x ++) {
float *a = CCG_grid_elem_no(&key, faceGridData, x, y );
float *b = CCG_grid_elem_no(&key, faceGridData, x + 1, y);
float *c = CCG_grid_elem_no(&key, faceGridData, x + 1, y + 1);
float *d = CCG_grid_elem_no(&key, faceGridData, x, y + 1);
glNormal3fv(CCG_elem_no(&key, a));
glVertex3fv(CCG_elem_co(&key, a));
glNormal3fv(CCG_elem_no(&key, b));
glVertex3fv(CCG_elem_co(&key, b));
normal_float_to_short_v3(&varray[start], a);
normal_float_to_short_v3(&varray[start + 4], b);
normal_float_to_short_v3(&varray[start + 8], c);
normal_float_to_short_v3(&varray[start + 12], d);
start += 16;
}
glEnd();
}
}
else {
glBegin(GL_QUADS);
for (y = 0; y < gridFaces; y += step) {
for (x = 0; x < gridFaces; x += step) {
float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
float *b = CCG_grid_elem_co(&key, faceGridData, x + step, y + 0);
float *c = CCG_grid_elem_co(&key, faceGridData, x + step, y + step);
float *d = CCG_grid_elem_co(&key, faceGridData, x, y + step);
for (y = 0; y < gridFaces; y ++) {
for (x = 0; x < gridFaces; x ++) {
float no[3];
float *a = CCG_grid_elem_co(&key, faceGridData, x, y );
float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y );
float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
ccgDM_glNormalFast(a, b, c, d);
ccgDM_NormalFast(a, b, c, d, no);
normal_float_to_short_v3(&varray[start], no);
normal_float_to_short_v3(&varray[start + 4], no);
normal_float_to_short_v3(&varray[start + 8], no);
normal_float_to_short_v3(&varray[start + 12], no);
glVertex3fv(d);
glVertex3fv(c);
glVertex3fv(b);
glVertex3fv(a);
start += 16;
}
}
glEnd();
}
}
}
}
/* Only used by non-editmesh types */
static void ccgDM_buffer_copy_triangles(DerivedMesh *dm, float *varray_,
int *mat_orig_to_new, void *UNUSED(user_data))
{
GPUBufferMaterial *gpumat;
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
unsigned int *varray = (unsigned int *)varray_;
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int i, totface = ccgSubSurf_getNumFaces(ss);
int matnr = -1, start;
int totloops = 0;
CCG_key_top_level(&key, ss);
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
if (faceFlags) {
matnr = faceFlags[index].mat_nr;
}
else {
matnr = 0;
}
for (S = 0; S < numVerts; S++) {
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
gpumat = dm->drawObject->materials + mat_orig_to_new[matnr];
start = gpumat->counter;
varray[start] = totloops + 3;
varray[start + 1] = totloops + 2;
varray[start + 2] = totloops + 1;
varray[start + 3] = totloops + 3;
varray[start + 4] = totloops + 1;
varray[start + 5] = totloops;
gpumat->counter += 6;
totloops += 4;
}
}
}
}
}
/* Only used by non-editmesh types */
static void ccgDM_buffer_copy_vertex(DerivedMesh *dm, float *varray,
int *UNUSED(mat_orig_to_new), void *UNUSED(user_data))
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int i, totface = ccgSubSurf_getNumFaces(ss);
int start = 0;
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
for (S = 0; S < numVerts; S++) {
CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
float *a = CCG_grid_elem_co(&key, faceGridData, x, y);
float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
copy_v3_v3(&varray[start], a);
copy_v3_v3(&varray[start + 3], b);
copy_v3_v3(&varray[start + 6], c);
copy_v3_v3(&varray[start + 9], d);
start += 12;
}
}
}
}
}
static void copy_mcol_uc3(unsigned char *v, unsigned char *col)
{
v[0] = col[3];
v[1] = col[2];
v[2] = col[1];
}
/* Only used by non-editmesh types */
static void ccgDM_buffer_copy_color(DerivedMesh *dm, float *varray_,
int *UNUSED(mat_orig_to_new), void *user_data)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
unsigned char *varray = (unsigned char *)varray_;
unsigned char *mcol = (unsigned char *)user_data;
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int i, totface = ccgSubSurf_getNumFaces(ss);
int start = 0;
int iface = 0;
CCG_key_top_level(&key, ss);
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
for (S = 0; S < numVerts; S++) {
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
copy_mcol_uc3(&varray[start], &mcol[iface * 16]);
copy_mcol_uc3(&varray[start + 3], &mcol[iface * 16 + 12]);
copy_mcol_uc3(&varray[start + 6], &mcol[iface * 16 + 8]);
copy_mcol_uc3(&varray[start + 9], &mcol[iface * 16 + 4]);
start += 12;
iface++;
}
}
}
}
}
static void ccgDM_buffer_copy_uv(DerivedMesh *dm, float *varray,
int *UNUSED(mat_orig_to_new), void *UNUSED(user_data))
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int i, totface = ccgSubSurf_getNumFaces(ss);
int start = 0;
CCG_key_top_level(&key, ss);
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
for (S = 0; S < numVerts; S++) {
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
copy_v2_v2(&varray[start], tf->uv[0]);
copy_v2_v2(&varray[start + 2], tf->uv[3]);
copy_v2_v2(&varray[start + 4], tf->uv[2]);
copy_v2_v2(&varray[start + 6], tf->uv[1]);
tf++;
start += 8;
}
}
}
}
}
static void ccgDM_buffer_copy_uv_texpaint(DerivedMesh *dm, float *varray, int *UNUSED(mat_orig_to_new), void *UNUSED(user))
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int i, totface = ccgSubSurf_getNumFaces(ss);
int start = 0;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int totmaterial = dm->totmat;
MTFace **mtface_base;
MTFace *stencil_base;
int stencil;
CCG_key_top_level(&key, ss);
/* should have been checked for before, reassert */
BLI_assert(DM_get_tessface_data_layer(dm, CD_MTFACE));
mtface_base = MEM_mallocN(totmaterial * sizeof(*mtface_base), "texslots");
for (i = 0; i < totmaterial; i++) {
mtface_base[i] = DM_paint_uvlayer_active_get(dm, i);
}
stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE);
stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil);
start = 0;
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
int matnr;
if (faceFlags) {
matnr = faceFlags[index].mat_nr;
}
else {
matnr = 0;
}
for (S = 0; S < numVerts; S++) {
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
/* divide by 16, gives us current tface */
unsigned int i_tf = start / 16;
copy_v2_v2(&varray[start], mtface_base[matnr][i_tf].uv[0]);
copy_v2_v2(&varray[start + 2], stencil_base[i_tf].uv[0]);
copy_v2_v2(&varray[start + 4], mtface_base[matnr][i_tf].uv[3]);
copy_v2_v2(&varray[start + 6], stencil_base[i_tf].uv[3]);
copy_v2_v2(&varray[start + 8], mtface_base[matnr][i_tf].uv[2]);
copy_v2_v2(&varray[start + 10], stencil_base[i_tf].uv[2]);
copy_v2_v2(&varray[start + 12], mtface_base[matnr][i_tf].uv[1]);
copy_v2_v2(&varray[start + 14], stencil_base[i_tf].uv[1]);
start += 16;
}
}
}
}
MEM_freeN(mtface_base);
}
static void ccgDM_copy_gpu_data(DerivedMesh *dm, int type, float *varray,
int *mat_orig_to_new, void *user_data)
{
switch(type) {
case GPU_BUFFER_VERTEX:
ccgDM_buffer_copy_vertex(dm, varray, mat_orig_to_new, NULL);
break;
case GPU_BUFFER_NORMAL:
ccgDM_buffer_copy_normal(dm, varray, mat_orig_to_new, NULL);
break;
case GPU_BUFFER_UV:
ccgDM_buffer_copy_uv(dm, varray, mat_orig_to_new, NULL);
break;
case GPU_BUFFER_UV_TEXPAINT:
ccgDM_buffer_copy_uv_texpaint(dm, varray, mat_orig_to_new, NULL);
break;
case GPU_BUFFER_COLOR:
ccgDM_buffer_copy_color(dm, varray, mat_orig_to_new, user_data);
break;
case GPU_BUFFER_TRIANGLES:
ccgDM_buffer_copy_triangles(dm, varray, mat_orig_to_new, NULL);
break;
default:
break;
}
}
typedef struct {
int elements;
int loops;
int polys;
} GPUMaterialInfo;
static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm) {
GPUBufferMaterial *mat;
int *mat_orig_to_new;
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
GPUDrawObject *gdo;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int totmat = (faceFlags) ? dm->totmat : 1;
GPUMaterialInfo *matinfo;
int i, curmat, curelement, totface;
/* object contains at least one material (default included) so zero means uninitialized dm */
BLI_assert(totmat != 0);
totface = ccgSubSurf_getNumFaces(ss);
matinfo = MEM_callocN(sizeof(*matinfo) * totmat, "GPU_drawobject_new.mat_orig_to_new");
if (faceFlags) {
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int numVerts = ccgSubSurf_getFaceNumVerts(f);
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
int new_matnr = faceFlags[index].mat_nr;
matinfo[new_matnr].elements += numVerts * gridFaces * gridFaces * 6;
matinfo[new_matnr].loops += numVerts * gridFaces * gridFaces * 4;
matinfo[new_matnr].polys++;
}
}
else {
for (i = 0; i < totface; i++) {
matinfo[0].elements += gridFaces * gridFaces * 6;
matinfo[0].loops += gridFaces * gridFaces * 4;
matinfo[0].polys++;
}
}
/* create the GPUDrawObject */
gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
gdo->totvert = ccgSubSurf_getNumFinalFaces(ss) * 6;
gdo->totedge = ccgSubSurf_getNumFinalEdges(ss) * 2;
/* count the number of materials used by this DerivedMesh */
for (i = 0; i < totmat; i++) {
if (matinfo[i].elements > 0)
gdo->totmaterial++;
}
/* allocate an array of materials used by this DerivedMesh */
gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial,
"GPUDrawObject.materials");
/* initialize the materials array */
for (i = 0, curmat = 0, curelement = 0; i < totmat; i++) {
if (matinfo[i].elements > 0) {
gdo->materials[curmat].start = curelement;
gdo->materials[curmat].totelements = matinfo[i].elements;
gdo->materials[curmat].totloops = matinfo[i].loops;
gdo->materials[curmat].mat_nr = i;
gdo->materials[curmat].totpolys = matinfo[i].polys;
gdo->materials[curmat].polys = MEM_mallocN(sizeof(int) * matinfo[0].polys, "GPUBufferMaterial.polys");
curelement += matinfo[i].elements;
curmat++;
}
}
/* store total number of points used for triangles */
gdo->tot_triangle_point = curelement;
mat_orig_to_new = MEM_callocN(sizeof(*mat_orig_to_new) * totmat,
"GPUDrawObject.mat_orig_to_new");
/* build a map from the original material indices to the new
* GPUBufferMaterial indices */
for (i = 0; i < gdo->totmaterial; i++) {
mat_orig_to_new[gdo->materials[i].mat_nr] = i;
gdo->materials[i].counter = 0;
}
if (faceFlags) {
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
int new_matnr = faceFlags[index].mat_nr;
mat = &gdo->materials[mat_orig_to_new[new_matnr]];
mat->polys[mat->counter++] = i;
}
}
else {
mat = &gdo->materials[0];
for (i = 0; i < totface; i++)
mat->polys[mat->counter++] = i;
}
MEM_freeN(mat_orig_to_new);
MEM_freeN(matinfo);
return gdo;
}
/* Only used by non-editmesh types */
static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], bool fast, DMSetMaterial setMaterial)
{
int a;
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
if (ccgdm->pbvh && ccgdm->multires.mmd) {
if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
setMaterial, false, fast);
glShadeModel(GL_FLAT);
}
return;
}
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
glShadeModel(GL_SMOOTH);
for (a = 0; a < dm->drawObject->totmaterial; a++) {
if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, dm->drawObject->materials[a].start,
dm->drawObject->materials[a].totelements);
}
}
GPU_buffer_unbind();
}
/* Only used by non-editmesh types */
static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
DMSetMaterial setMaterial,
@ -2228,18 +2614,15 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
int colType = CD_TEXTURE_MCOL;
MCol *mcol = dm->getTessFaceDataArray(dm, colType);
MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
MTFace *tf_stencil_base = NULL;
MTFace *tf_stencil = NULL;
MTFace *tf_base;
short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
DMFlagMat *faceFlags = ccgdm->faceFlags;
DMDrawOption draw_option;
int i, totface, gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int gridOffset = 0;
int mat_nr_cache = -1;
(void) compareDrawOptions;
int i, totpoly;
bool flush;
bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
unsigned int next_actualFace;
unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
int mat_index;
int tot_element, start_element;
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
@ -2253,210 +2636,96 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
mcol = dm->getTessFaceDataArray(dm, colType);
}
totface = ccgSubSurf_getNumFaces(ss);
if (flag & DM_DRAW_USE_TEXPAINT_UV) {
int stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE);
tf_stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil);
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
if (flag & DM_DRAW_USE_TEXPAINT_UV)
GPU_texpaint_uv_setup(dm);
else
GPU_uv_setup(dm);
if (mcol) {
GPU_color_setup(dm, colType);
}
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
unsigned char *cp = NULL;
short (*ln)[4][3] = NULL;
int mat_nr;
next_actualFace = 0;
if (faceFlags) {
drawSmooth = (lnors || (faceFlags[origIndex].flag & ME_SMOOTH));
mat_nr = faceFlags[origIndex].mat_nr;
}
else {
drawSmooth = 1;
mat_nr = 0;
}
glShadeModel(GL_SMOOTH);
/* lastFlag = 0; */ /* UNUSED */
for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
next_actualFace = bufmat->polys[0];
totpoly = bufmat->totpolys;
/* texture painting, handle the correct uv layer here */
if (flag & DM_DRAW_USE_TEXPAINT_UV) {
if (mat_nr != mat_nr_cache) {
tf_base = DM_paint_uvlayer_active_get(dm, mat_nr);
tot_element = 0;
start_element = bufmat->start;
mat_nr_cache = mat_nr;
for (i = 0; i < totpoly; i++) {
int polyindex = bufmat->polys[i];
CCGFace *f = ccgdm->faceMap[polyindex].face;
int numVerts = ccgSubSurf_getFaceNumVerts(f);
int index = ccgDM_getFaceMapIndex(ss, f);
int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
int mat_nr;
int facequads = numVerts * gridFaces * gridFaces;
int actualFace = ccgdm->faceMap[polyindex].startFace;
if (i != totpoly - 1) {
polyindex = bufmat->polys[i + 1];
next_actualFace = ccgdm->faceMap[polyindex].startFace;
}
tf = tf_base ? tf_base + gridOffset : NULL;
tf_stencil = tf_stencil_base ? tf_stencil_base + gridOffset : NULL;
gridOffset += gridFaces * gridFaces * numVerts;
}
if (drawParams) {
MTexPoly tpoly;
if (tf) {
ME_MTEXFACE_CPY(&tpoly, tf);
}
draw_option = drawParams(tf ? &tpoly : NULL, (mcol != NULL), mat_nr);
}
else if (index != ORIGINDEX_NONE)
draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL;
else
draw_option = GPU_enable_material(mat_nr, NULL) ? DM_DRAW_OPTION_NORMAL : DM_DRAW_OPTION_SKIP;
if (lnors) {
ln = lnors;
lnors += gridFaces * gridFaces * numVerts;
}
if (draw_option == DM_DRAW_OPTION_SKIP) {
if (tf) tf += gridFaces * gridFaces * numVerts;
if (mcol) mcol += gridFaces * gridFaces * numVerts * 4;
continue;
}
/* flag 1 == use vertex colors */
if (mcol) {
if (draw_option != DM_DRAW_OPTION_NO_MCOL)
cp = (unsigned char *)mcol;
mcol += gridFaces * gridFaces * numVerts * 4;
}
for (S = 0; S < numVerts; S++) {
CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
CCGElem *a, *b;
if (ln) {
glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
float *a_co = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
float *b_co = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
float *c_co = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
float *d_co = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
if (tf) glTexCoord2fv(tf->uv[1]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[1]);
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
glNormal3sv(ln[0][1]);
glVertex3fv(d_co);
if (tf) glTexCoord2fv(tf->uv[2]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[2]);
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
glNormal3sv(ln[0][2]);
glVertex3fv(c_co);
if (tf) glTexCoord2fv(tf->uv[3]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[3]);
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
glNormal3sv(ln[0][3]);
glVertex3fv(b_co);
if (tf) glTexCoord2fv(tf->uv[0]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[0]);
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
glNormal3sv(ln[0][0]);
glVertex3fv(a_co);
if (tf) tf++;
if (tf_stencil) tf_stencil++;
if (cp) cp += 16;
ln++;
}
}
glEnd();
}
else if (drawSmooth) {
glShadeModel(GL_SMOOTH);
for (y = 0; y < gridFaces; y++) {
glBegin(GL_QUAD_STRIP);
for (x = 0; x < gridFaces; x++) {
a = CCG_grid_elem(&key, faceGridData, x, y + 0);
b = CCG_grid_elem(&key, faceGridData, x, y + 1);
if (tf) glTexCoord2fv(tf->uv[0]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[0]);
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
glNormal3fv(CCG_elem_no(&key, a));
glVertex3fv(CCG_elem_co(&key, a));
if (tf) glTexCoord2fv(tf->uv[1]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[1]);
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
glNormal3fv(CCG_elem_no(&key, b));
glVertex3fv(CCG_elem_co(&key, b));
if (x != gridFaces - 1) {
if (tf) tf++;
if (tf_stencil) tf_stencil++;
if (cp) cp += 16;
}
}
a = CCG_grid_elem(&key, faceGridData, x, y + 0);
b = CCG_grid_elem(&key, faceGridData, x, y + 1);
if (tf) glTexCoord2fv(tf->uv[3]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[3]);
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
glNormal3fv(CCG_elem_no(&key, a));
glVertex3fv(CCG_elem_co(&key, a));
if (tf) glTexCoord2fv(tf->uv[2]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[2]);
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
glNormal3fv(CCG_elem_no(&key, b));
glVertex3fv(CCG_elem_co(&key, b));
if (tf) tf++;
if (tf_stencil) tf_stencil++;
if (cp) cp += 16;
glEnd();
}
if (faceFlags) {
mat_nr = faceFlags[origIndex].mat_nr;
}
else {
glShadeModel((cp) ? GL_SMOOTH : GL_FLAT);
glBegin(GL_QUADS);
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
float *a_co = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
float *b_co = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
float *c_co = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
float *d_co = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
mat_nr = 0;
}
ccgDM_glNormalFast(a_co, b_co, c_co, d_co);
if (tf) glTexCoord2fv(tf->uv[1]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[1]);
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
glVertex3fv(d_co);
if (tf) glTexCoord2fv(tf->uv[2]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[2]);
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
glVertex3fv(c_co);
if (tf) glTexCoord2fv(tf->uv[3]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[3]);
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
glVertex3fv(b_co);
if (tf) glTexCoord2fv(tf->uv[0]);
if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[0]);
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
glVertex3fv(a_co);
if (tf) tf++;
if (tf_stencil) tf_stencil++;
if (cp) cp += 16;
}
if (drawParams) {
MTexPoly tpoly;
if (tf) {
ME_MTEXFACE_CPY(&tpoly, tf + actualFace);
}
glEnd();
draw_option = drawParams((use_tface && tf) ? &tpoly : NULL, (mcol != NULL), mat_nr);
}
else if (index != ORIGINDEX_NONE)
draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL;
else
draw_option = DM_DRAW_OPTION_NORMAL;
/* flush buffer if current triangle isn't drawable or it's last triangle */
flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1);
if (!flush && compareDrawOptions) {
/* also compare draw options and flush buffer if they're different
* need for face selection highlight in edit mode */
flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
}
if (flush) {
if (draw_option != DM_DRAW_OPTION_SKIP)
tot_element += facequads * 6;
if (tot_element) {
if (mcol && draw_option != DM_DRAW_OPTION_NO_MCOL)
GPU_color_switch(1);
else
GPU_color_switch(0);
GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, start_element, tot_element);
}
start_element = tot_element;
}
else {
tot_element += facequads * 6;
}
}
}
GPU_buffer_unbind();
}
static void ccgDM_drawFacesTex(DerivedMesh *dm,
@ -3440,7 +3709,9 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
ccgdm->dm.gpuObjectNew = ccgDM_GPUObjectNew;
ccgdm->dm.copy_gpu_data = ccgDM_copy_gpu_data;
ccgdm->dm.release = ccgDM_release;
ccgdm->ss = ss;

View File

@ -48,6 +48,10 @@ struct GSet;
struct GPUVertPointLink;
struct PBVH;
typedef void (*GPUBufferCopyFunc)(DerivedMesh *dm, float *varray, int *index,
int *mat_orig_to_new, void *user_data);
typedef struct GPUBuffer {
int size; /* in bytes */
void *pointer; /* used with vertex arrays */
@ -58,7 +62,11 @@ typedef struct GPUBuffer {
typedef struct GPUBufferMaterial {
/* range of points used for this material */
int start;
int totpoint;
int totelements;
int totloops;
int *polys; /* array of polygons for this material */
int totpolys; /* total polygons in polys */
int counter; /* general purpose counter, initialize first! */
/* original material index */
short mat_nr;
@ -88,9 +96,7 @@ typedef struct GPUDrawObject {
GPUBuffer *colors;
GPUBuffer *edges;
GPUBuffer *uvedges;
/* for each triangle, the original MFace index */
int *triangle_to_mface;
GPUBuffer *triangles; /* triangle index buffer */
/* for each original vertex, the list of related points */
struct GPUVertPointLink *vert_points;
@ -103,12 +109,15 @@ typedef struct GPUDrawObject {
#endif
int colType;
int index_setup; /* how indices are setup, starting from start of buffer or start of material */
GPUBufferMaterial *materials;
int totmaterial;
int tot_triangle_point;
int tot_loose_point;
/* different than total loops since ngons get tesselated still */
int tot_loop_verts;
/* caches of the original DerivedMesh values */
int totvert;
@ -119,6 +128,19 @@ typedef struct GPUDrawObject {
int tot_edge_drawn;
} GPUDrawObject;
/* currently unused */
// #define USE_GPU_POINT_LINK
typedef struct GPUVertPointLink {
#ifdef USE_GPU_POINT_LINK
struct GPUVertPointLink *next;
#endif
/* -1 means uninitialized */
int point_index;
} GPUVertPointLink;
/* used for GLSL materials */
typedef struct GPUAttrib {
int index;
@ -129,12 +151,24 @@ typedef struct GPUAttrib {
void GPU_global_buffer_pool_free(void);
void GPU_global_buffer_pool_free_unused(void);
GPUBuffer *GPU_buffer_alloc(int size, bool force_vertex_arrays);
GPUBuffer *GPU_buffer_alloc(size_t size, bool force_vertex_arrays);
void GPU_buffer_free(GPUBuffer *buffer);
GPUDrawObject *GPU_drawobject_new(struct DerivedMesh *dm);
void GPU_drawobject_free(struct DerivedMesh *dm);
/* flag that controls data type to fill buffer with, a modifier will prepare. */
typedef enum {
GPU_BUFFER_VERTEX = 0,
GPU_BUFFER_NORMAL,
GPU_BUFFER_COLOR,
GPU_BUFFER_UV,
GPU_BUFFER_UV_TEXPAINT,
GPU_BUFFER_EDGE,
GPU_BUFFER_UVEDGE,
GPU_BUFFER_TRIANGLES
} GPUBufferType;
/* called before drawing */
void GPU_vertex_setup(struct DerivedMesh *dm);
void GPU_normal_setup(struct DerivedMesh *dm);
@ -144,8 +178,11 @@ void GPU_texpaint_uv_setup(struct DerivedMesh *dm);
void GPU_color_setup(struct DerivedMesh *dm, int colType);
void GPU_edge_setup(struct DerivedMesh *dm); /* does not mix with other data */
void GPU_uvedge_setup(struct DerivedMesh *dm);
void GPU_triangle_setup(struct DerivedMesh *dm);
int GPU_attrib_element_size(GPUAttrib data[], int numdata);
void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata);
void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata, int element_size);
/* can't lock more than one buffer at once */
void *GPU_buffer_lock(GPUBuffer *buffer);
@ -161,6 +198,9 @@ void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start,
/* called after drawing */
void GPU_buffer_unbind(void);
/* only unbind interleaved data */
void GPU_interleaved_attrib_unbind(void);
/* Buffers for non-DerivedMesh drawing */
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
@ -196,7 +236,7 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, struct CCGElem **gr
/* draw */
void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
bool wireframe);
bool wireframe, bool fast);
/* debug PBVH draw*/
void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf);

View File

@ -69,6 +69,35 @@ typedef enum {
GPU_BUFFER_ELEMENT_STATE = (1 << 5),
} GPUBufferState;
typedef struct {
GLenum gl_buffer_type;
int num_components; /* number of data components for one vertex */
} GPUBufferTypeSettings;
static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type);
const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
/* vertex */
{GL_ARRAY_BUFFER_ARB, 3},
/* normal */
{GL_ARRAY_BUFFER_ARB, 4}, /* we copy 3 shorts per normal but we add a fourth for alignment */
/* mcol */
{GL_ARRAY_BUFFER_ARB, 3},
/* uv */
{GL_ARRAY_BUFFER_ARB, 2},
/* uv for texpaint */
{GL_ARRAY_BUFFER_ARB, 4},
/* edge */
{GL_ELEMENT_ARRAY_BUFFER_ARB, 2},
/* uv edge */
{GL_ELEMENT_ARRAY_BUFFER_ARB, 4},
/* triangles, 1 point since we are allocating from tottriangle points, which account for all points */
{GL_ELEMENT_ARRAY_BUFFER_ARB, 1},
/* fast triangles */
{GL_ELEMENT_ARRAY_BUFFER_ARB, 1},
};
#define MAX_GPU_ATTRIB_DATA 32
#define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n))
@ -221,11 +250,12 @@ void GPU_global_buffer_pool_free_unused(void)
*
* Thread-unsafe version for internal usage only.
*/
static GPUBuffer *gpu_buffer_alloc_intern(int size, bool use_VBO)
static GPUBuffer *gpu_buffer_alloc_intern(size_t size, bool use_VBO)
{
GPUBufferPool *pool;
GPUBuffer *buf;
int i, bufsize, bestfit = -1;
int i, bestfit = -1;
size_t bufsize;
/* bad case, leads to leak of buf since buf->pointer will allocate
* NULL, leading to return without cleanup. In any case better detect early
@ -290,8 +320,11 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size, bool use_VBO)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
else {
static int time = 0;
buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer");
time++;
/* purpose of this seems to be dealing with
* out-of-memory errors? looks a bit iffy to me
* though, at least on Linux I expect malloc() would
@ -308,7 +341,7 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size, bool use_VBO)
}
/* Same as above, but safe for threading. */
GPUBuffer *GPU_buffer_alloc(int size, bool force_vertex_arrays)
GPUBuffer *GPU_buffer_alloc(size_t size, bool force_vertex_arrays)
{
GPUBuffer *buffer;
bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO) && !force_vertex_arrays;
@ -383,197 +416,22 @@ void GPU_buffer_free(GPUBuffer *buffer)
BLI_mutex_unlock(&buffer_mutex);
}
#if 0 /* currently unused */
# define USE_GPU_POINT_LINK
#endif
typedef struct GPUVertPointLink {
#ifdef USE_GPU_POINT_LINK
struct GPUVertPointLink *next;
#endif
/* -1 means uninitialized */
int point_index;
} GPUVertPointLink;
/* add a new point to the list of points related to a particular
* vertex */
#ifdef USE_GPU_POINT_LINK
static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
{
GPUVertPointLink *lnk;
lnk = &gdo->vert_points[vert_index];
/* if first link is in use, add a new link at the end */
if (lnk->point_index != -1) {
/* get last link */
for (; lnk->next; lnk = lnk->next) ;
/* add a new link from the pool */
lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage];
gdo->vert_points_usage++;
}
lnk->point_index = point_index;
}
#else
static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
{
GPUVertPointLink *lnk;
lnk = &gdo->vert_points[vert_index];
if (lnk->point_index == -1) {
lnk->point_index = point_index;
}
}
#endif /* USE_GPU_POINT_LINK */
/* update the vert_points and triangle_to_mface fields with a new
* triangle */
static void gpu_drawobject_add_triangle(GPUDrawObject *gdo,
int base_point_index,
int face_index,
int v1, int v2, int v3)
{
int i, v[3] = {v1, v2, v3};
for (i = 0; i < 3; i++)
gpu_drawobject_add_vert_point(gdo, v[i], base_point_index + i);
gdo->triangle_to_mface[base_point_index / 3] = face_index;
}
/* for each vertex, build a list of points related to it; these lists
* are stored in an array sized to the number of vertices */
static void gpu_drawobject_init_vert_points(GPUDrawObject *gdo, const MFace *f, int totface, int totmat)
{
GPUBufferMaterial *mat;
int i, *mat_orig_to_new;
mat_orig_to_new = MEM_callocN(sizeof(*mat_orig_to_new) * totmat,
"GPUDrawObject.mat_orig_to_new");
/* allocate the array and space for links */
gdo->vert_points = MEM_mallocN(sizeof(GPUVertPointLink) * gdo->totvert,
"GPUDrawObject.vert_points");
#ifdef USE_GPU_POINT_LINK
gdo->vert_points_mem = MEM_callocN(sizeof(GPUVertPointLink) * gdo->tot_triangle_point,
"GPUDrawObject.vert_points_mem");
gdo->vert_points_usage = 0;
#endif
/* build a map from the original material indices to the new
* GPUBufferMaterial indices */
for (i = 0; i < gdo->totmaterial; i++)
mat_orig_to_new[gdo->materials[i].mat_nr] = i;
/* -1 indicates the link is not yet used */
for (i = 0; i < gdo->totvert; i++) {
#ifdef USE_GPU_POINT_LINK
gdo->vert_points[i].link = NULL;
#endif
gdo->vert_points[i].point_index = -1;
}
for (i = 0; i < totface; i++, f++) {
mat = &gdo->materials[mat_orig_to_new[f->mat_nr]];
/* add triangle */
gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
i, f->v1, f->v2, f->v3);
mat->totpoint += 3;
/* add second triangle for quads */
if (f->v4) {
gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
i, f->v3, f->v4, f->v1);
mat->totpoint += 3;
}
}
/* map any unused vertices to loose points */
for (i = 0; i < gdo->totvert; i++) {
if (gdo->vert_points[i].point_index == -1) {
gdo->vert_points[i].point_index = gdo->tot_triangle_point + gdo->tot_loose_point;
gdo->tot_loose_point++;
}
}
MEM_freeN(mat_orig_to_new);
}
/* see GPUDrawObject's structure definition for a description of the
* data being initialized here */
GPUDrawObject *GPU_drawobject_new(DerivedMesh *dm)
{
GPUDrawObject *gdo;
const MFace *mface;
int totmat = dm->totmat;
int *points_per_mat;
int i, curmat, curpoint, totface;
/* object contains at least one material (default included) so zero means uninitialized dm */
BLI_assert(totmat != 0);
mface = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
/* get the number of points used by each material, treating
* each quad as two triangles */
points_per_mat = MEM_callocN(sizeof(*points_per_mat) * totmat, "GPU_drawobject_new.mat_orig_to_new");
for (i = 0; i < totface; i++)
points_per_mat[mface[i].mat_nr] += mface[i].v4 ? 6 : 3;
/* create the GPUDrawObject */
gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
gdo->totvert = dm->getNumVerts(dm);
gdo->totedge = dm->getNumEdges(dm);
/* count the number of materials used by this DerivedMesh */
for (i = 0; i < totmat; i++) {
if (points_per_mat[i] > 0)
gdo->totmaterial++;
}
/* allocate an array of materials used by this DerivedMesh */
gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial,
"GPUDrawObject.materials");
/* initialize the materials array */
for (i = 0, curmat = 0, curpoint = 0; i < totmat; i++) {
if (points_per_mat[i] > 0) {
gdo->materials[curmat].start = curpoint;
gdo->materials[curmat].totpoint = 0;
gdo->materials[curmat].mat_nr = i;
curpoint += points_per_mat[i];
curmat++;
}
}
/* store total number of points used for triangles */
gdo->tot_triangle_point = curpoint;
gdo->triangle_to_mface = MEM_mallocN(sizeof(int) * (gdo->tot_triangle_point / 3),
"GPUDrawObject.triangle_to_mface");
gpu_drawobject_init_vert_points(gdo, mface, totface, totmat);
MEM_freeN(points_per_mat);
return gdo;
}
void GPU_drawobject_free(DerivedMesh *dm)
{
GPUDrawObject *gdo;
int i;
if (!dm || !(gdo = dm->drawObject))
return;
for (i = 0; i < gdo->totmaterial; i++) {
if (gdo->materials[i].polys)
MEM_freeN(gdo->materials[i].polys);
}
MEM_freeN(gdo->materials);
MEM_freeN(gdo->triangle_to_mface);
MEM_freeN(gdo->vert_points);
if (gdo->vert_points)
MEM_freeN(gdo->vert_points);
#ifdef USE_GPU_POINT_LINK
MEM_freeN(gdo->vert_points_mem);
#endif
@ -584,6 +442,7 @@ void GPU_drawobject_free(DerivedMesh *dm)
GPU_buffer_free(gdo->colors);
GPU_buffer_free(gdo->edges);
GPU_buffer_free(gdo->uvedges);
GPU_buffer_free(gdo->triangles);
MEM_freeN(gdo);
dm->drawObject = NULL;
@ -605,20 +464,18 @@ static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, int si
return buffer;
}
typedef void (*GPUBufferCopyFunc)(
DerivedMesh *dm, float *varray, int *index,
const int *mat_orig_to_new, const void *user_data);
static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
int vector_size, int size, GLenum target,
void *user, GPUBufferCopyFunc copy_f)
int type, void *user)
{
GPUBufferPool *pool;
GPUBuffer *buffer;
float *varray;
int *mat_orig_to_new;
int *cur_index_per_mat;
int i;
const GPUBufferTypeSettings *ts = &gpu_buffer_type_settings[type];
GLenum target = ts->gl_buffer_type;
int num_components = ts->num_components;
int size = gpu_buffer_size_from_type(dm, type);
bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO);
GLboolean uploaded;
@ -634,11 +491,9 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat,
"GPU_buffer_setup.mat_orig_to_new");
cur_index_per_mat = MEM_mallocN(sizeof(int) * object->totmaterial,
"GPU_buffer_setup.cur_index_per_mat");
for (i = 0; i < object->totmaterial; i++) {
/* for each material, the current index to copy data to */
cur_index_per_mat[i] = object->materials[i].start * vector_size;
object->materials[i].counter = object->materials[i].start * num_components;
/* map from original material index to new
* GPUBufferMaterial index */
@ -675,7 +530,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
uploaded = GL_FALSE;
/* attempt to upload the data to the VBO */
while (uploaded == GL_FALSE) {
(*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user);
dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user);
/* glUnmapBuffer returns GL_FALSE if
* the data store is corrupted; retry
* in that case */
@ -692,11 +547,10 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
if (buffer) {
varray = buffer->pointer;
(*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user);
dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user);
}
}
MEM_freeN(cur_index_per_mat);
MEM_freeN(mat_orig_to_new);
BLI_mutex_unlock(&buffer_mutex);
@ -704,375 +558,6 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
return buffer;
}
static void GPU_buffer_copy_vertex(
DerivedMesh *dm, float *varray,
int *index, const int *mat_orig_to_new, const void *UNUSED(user))
{
const MVert *mvert;
const MFace *f;
int i, j, start, totface;
mvert = dm->getVertArray(dm);
f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
start = index[mat_orig_to_new[f->mat_nr]];
/* v1 v2 v3 */
copy_v3_v3(&varray[start], mvert[f->v1].co);
copy_v3_v3(&varray[start + 3], mvert[f->v2].co);
copy_v3_v3(&varray[start + 6], mvert[f->v3].co);
index[mat_orig_to_new[f->mat_nr]] += 9;
if (f->v4) {
/* v3 v4 v1 */
copy_v3_v3(&varray[start + 9], mvert[f->v3].co);
copy_v3_v3(&varray[start + 12], mvert[f->v4].co);
copy_v3_v3(&varray[start + 15], mvert[f->v1].co);
index[mat_orig_to_new[f->mat_nr]] += 9;
}
}
/* copy loose points */
j = dm->drawObject->tot_triangle_point * 3;
for (i = 0; i < dm->drawObject->totvert; i++) {
if (dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_triangle_point) {
copy_v3_v3(&varray[j], mvert[i].co);
j += 3;
}
}
}
static void GPU_buffer_copy_normal(
DerivedMesh *dm, float *varray, int *index,
const int *mat_orig_to_new, const void *UNUSED(user))
{
int i, totface;
int start;
float f_no[3];
const float *nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
short (*tlnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
const MVert *mvert = dm->getVertArray(dm);
const MFace *f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
const int smoothnormal = (f->flag & ME_SMOOTH);
start = index[mat_orig_to_new[f->mat_nr]];
index[mat_orig_to_new[f->mat_nr]] += f->v4 ? 18 : 9;
if (tlnors) {
short (*tlnor)[3] = tlnors[i];
/* Copy loop normals */
normal_short_to_float_v3(&varray[start], tlnor[0]);
normal_short_to_float_v3(&varray[start + 3], tlnor[1]);
normal_short_to_float_v3(&varray[start + 6], tlnor[2]);
if (f->v4) {
normal_short_to_float_v3(&varray[start + 9], tlnor[2]);
normal_short_to_float_v3(&varray[start + 12], tlnor[3]);
normal_short_to_float_v3(&varray[start + 15], tlnor[0]);
}
}
else if (smoothnormal) {
/* copy vertex normal */
normal_short_to_float_v3(&varray[start], mvert[f->v1].no);
normal_short_to_float_v3(&varray[start + 3], mvert[f->v2].no);
normal_short_to_float_v3(&varray[start + 6], mvert[f->v3].no);
if (f->v4) {
normal_short_to_float_v3(&varray[start + 9], mvert[f->v3].no);
normal_short_to_float_v3(&varray[start + 12], mvert[f->v4].no);
normal_short_to_float_v3(&varray[start + 15], mvert[f->v1].no);
}
}
else if (nors) {
/* copy cached face normal */
copy_v3_v3(&varray[start], &nors[i * 3]);
copy_v3_v3(&varray[start + 3], &nors[i * 3]);
copy_v3_v3(&varray[start + 6], &nors[i * 3]);
if (f->v4) {
copy_v3_v3(&varray[start + 9], &nors[i * 3]);
copy_v3_v3(&varray[start + 12], &nors[i * 3]);
copy_v3_v3(&varray[start + 15], &nors[i * 3]);
}
}
else {
/* calculate face normal */
if (f->v4)
normal_quad_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co, mvert[f->v4].co);
else
normal_tri_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co);
copy_v3_v3(&varray[start], f_no);
copy_v3_v3(&varray[start + 3], f_no);
copy_v3_v3(&varray[start + 6], f_no);
if (f->v4) {
copy_v3_v3(&varray[start + 9], f_no);
copy_v3_v3(&varray[start + 12], f_no);
copy_v3_v3(&varray[start + 15], f_no);
}
}
}
}
static void GPU_buffer_copy_uv(
DerivedMesh *dm, float *varray, int *index,
const int *mat_orig_to_new, const void *UNUSED(user))
{
int start;
int i, totface;
const MTFace *mtface;
const MFace *f;
if (!(mtface = DM_get_tessface_data_layer(dm, CD_MTFACE)))
return;
f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
start = index[mat_orig_to_new[f->mat_nr]];
/* v1 v2 v3 */
copy_v2_v2(&varray[start], mtface[i].uv[0]);
copy_v2_v2(&varray[start + 2], mtface[i].uv[1]);
copy_v2_v2(&varray[start + 4], mtface[i].uv[2]);
index[mat_orig_to_new[f->mat_nr]] += 6;
if (f->v4) {
/* v3 v4 v1 */
copy_v2_v2(&varray[start + 6], mtface[i].uv[2]);
copy_v2_v2(&varray[start + 8], mtface[i].uv[3]);
copy_v2_v2(&varray[start + 10], mtface[i].uv[0]);
index[mat_orig_to_new[f->mat_nr]] += 6;
}
}
}
static void GPU_buffer_copy_uv_texpaint(
DerivedMesh *dm, float *varray, int *index,
const int *mat_orig_to_new, const void *UNUSED(user))
{
int start;
int i, totface;
int totmaterial = dm->totmat;
const MTFace **mtface_base;
const MTFace *stencil_base;
int stencil;
const MFace *mf;
/* should have been checked for before, reassert */
BLI_assert(DM_get_tessface_data_layer(dm, CD_MTFACE));
mf = dm->getTessFaceArray(dm);
mtface_base = MEM_mallocN(totmaterial * sizeof(*mtface_base), "texslots");
for (i = 0; i < totmaterial; i++) {
mtface_base[i] = DM_paint_uvlayer_active_get(dm, i);
}
stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE);
stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, mf++) {
int mat_i = mf->mat_nr;
start = index[mat_orig_to_new[mat_i]];
/* v1 v2 v3 */
copy_v2_v2(&varray[start], mtface_base[mat_i][i].uv[0]);
copy_v2_v2(&varray[start + 2], stencil_base[i].uv[0]);
copy_v2_v2(&varray[start + 4], mtface_base[mat_i][i].uv[1]);
copy_v2_v2(&varray[start + 6], stencil_base[i].uv[1]);
copy_v2_v2(&varray[start + 8], mtface_base[mat_i][i].uv[2]);
copy_v2_v2(&varray[start + 10], stencil_base[i].uv[2]);
index[mat_orig_to_new[mat_i]] += 12;
if (mf->v4) {
/* v3 v4 v1 */
copy_v2_v2(&varray[start + 12], mtface_base[mat_i][i].uv[2]);
copy_v2_v2(&varray[start + 14], stencil_base[i].uv[2]);
copy_v2_v2(&varray[start + 16], mtface_base[mat_i][i].uv[3]);
copy_v2_v2(&varray[start + 18], stencil_base[i].uv[3]);
copy_v2_v2(&varray[start + 20], mtface_base[mat_i][i].uv[0]);
copy_v2_v2(&varray[start + 22], stencil_base[i].uv[0]);
index[mat_orig_to_new[mat_i]] += 12;
}
}
MEM_freeN(mtface_base);
}
static void copy_mcol_uc3(unsigned char *v, unsigned char *col)
{
v[0] = col[3];
v[1] = col[2];
v[2] = col[1];
}
/* treat varray_ as an array of MCol, four MCol's per face */
static void GPU_buffer_copy_mcol(
DerivedMesh *dm, float *varray_, int *index,
const int *mat_orig_to_new, const void *user)
{
int i, totface;
unsigned char *varray = (unsigned char *)varray_;
unsigned char *mcol = (unsigned char *)user;
const MFace *f = dm->getTessFaceArray(dm);
totface = dm->getNumTessFaces(dm);
for (i = 0; i < totface; i++, f++) {
int start = index[mat_orig_to_new[f->mat_nr]];
/* v1 v2 v3 */
copy_mcol_uc3(&varray[start], &mcol[i * 16]);
copy_mcol_uc3(&varray[start + 3], &mcol[i * 16 + 4]);
copy_mcol_uc3(&varray[start + 6], &mcol[i * 16 + 8]);
index[mat_orig_to_new[f->mat_nr]] += 9;
if (f->v4) {
/* v3 v4 v1 */
copy_mcol_uc3(&varray[start + 9], &mcol[i * 16 + 8]);
copy_mcol_uc3(&varray[start + 12], &mcol[i * 16 + 12]);
copy_mcol_uc3(&varray[start + 15], &mcol[i * 16]);
index[mat_orig_to_new[f->mat_nr]] += 9;
}
}
}
static void GPU_buffer_copy_edge(
DerivedMesh *dm, float *varray_, int *UNUSED(index),
const int *UNUSED(mat_orig_to_new), const void *UNUSED(user))
{
const MEdge *medge, *medge_base;
unsigned int *varray = (unsigned int *)varray_;
int i, totedge, iloose, inorm, iloosehidden, inormhidden;
int tot_loose_hidden = 0, tot_loose = 0;
int tot_hidden = 0, tot = 0;
medge_base = medge = dm->getEdgeArray(dm);
totedge = dm->getNumEdges(dm);
for (i = 0; i < totedge; i++, medge++) {
if (medge->flag & ME_EDGEDRAW) {
if (medge->flag & ME_LOOSEEDGE) tot_loose++;
else tot++;
}
else {
if (medge->flag & ME_LOOSEEDGE) tot_loose_hidden++;
else tot_hidden++;
}
}
inorm = 0;
inormhidden = tot;
iloose = tot + tot_hidden;
iloosehidden = iloose + tot_loose;
medge = medge_base;
for (i = 0; i < totedge; i++, medge++) {
if (medge->flag & ME_EDGEDRAW) {
if (medge->flag & ME_LOOSEEDGE) {
varray[iloose * 2] = dm->drawObject->vert_points[medge->v1].point_index;
varray[iloose * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
iloose++;
}
else {
varray[inorm * 2] = dm->drawObject->vert_points[medge->v1].point_index;
varray[inorm * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
inorm++;
}
}
else {
if (medge->flag & ME_LOOSEEDGE) {
varray[iloosehidden * 2] = dm->drawObject->vert_points[medge->v1].point_index;
varray[iloosehidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
iloosehidden++;
}
else {
varray[inormhidden * 2] = dm->drawObject->vert_points[medge->v1].point_index;
varray[inormhidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
inormhidden++;
}
}
}
dm->drawObject->tot_loose_edge_drawn = tot_loose;
dm->drawObject->loose_edge_offset = tot + tot_hidden;
dm->drawObject->tot_edge_drawn = tot;
}
static void GPU_buffer_copy_uvedge(
DerivedMesh *dm, float *varray, int *UNUSED(index),
const int *UNUSED(mat_orig_to_new), const void *UNUSED(user))
{
const MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
int i, j = 0;
if (!tf)
return;
for (i = 0; i < dm->numTessFaceData; i++, tf++) {
MFace mf;
dm->getTessFace(dm, i, &mf);
copy_v2_v2(&varray[j], tf->uv[0]);
copy_v2_v2(&varray[j + 2], tf->uv[1]);
copy_v2_v2(&varray[j + 4], tf->uv[1]);
copy_v2_v2(&varray[j + 6], tf->uv[2]);
if (!mf.v4) {
copy_v2_v2(&varray[j + 8], tf->uv[2]);
copy_v2_v2(&varray[j + 10], tf->uv[0]);
j += 12;
}
else {
copy_v2_v2(&varray[j + 8], tf->uv[2]);
copy_v2_v2(&varray[j + 10], tf->uv[3]);
copy_v2_v2(&varray[j + 12], tf->uv[3]);
copy_v2_v2(&varray[j + 14], tf->uv[0]);
j += 16;
}
}
}
typedef enum {
GPU_BUFFER_VERTEX = 0,
GPU_BUFFER_NORMAL,
GPU_BUFFER_COLOR,
GPU_BUFFER_UV,
GPU_BUFFER_UV_TEXPAINT,
GPU_BUFFER_EDGE,
GPU_BUFFER_UVEDGE,
} GPUBufferType;
typedef struct {
GPUBufferCopyFunc copy;
GLenum gl_buffer_type;
int vector_size;
} GPUBufferTypeSettings;
const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
{GPU_buffer_copy_vertex, GL_ARRAY_BUFFER_ARB, 3},
{GPU_buffer_copy_normal, GL_ARRAY_BUFFER_ARB, 3},
{GPU_buffer_copy_mcol, GL_ARRAY_BUFFER_ARB, 3},
{GPU_buffer_copy_uv, GL_ARRAY_BUFFER_ARB, 2},
{GPU_buffer_copy_uv_texpaint, GL_ARRAY_BUFFER_ARB, 4},
{GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2},
{GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4}
};
/* get the GPUDrawObject buffer associated with a type */
static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBufferType type)
{
@ -1091,6 +576,8 @@ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBuffer
return &gdo->edges;
case GPU_BUFFER_UVEDGE:
return &gdo->uvedges;
case GPU_BUFFER_TRIANGLES:
return &gdo->triangles;
default:
return NULL;
}
@ -1101,24 +588,26 @@ static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type)
{
switch (type) {
case GPU_BUFFER_VERTEX:
return sizeof(float) * 3 * (dm->drawObject->tot_triangle_point + dm->drawObject->tot_loose_point);
return sizeof(float) * gpu_buffer_type_settings[type].num_components * (dm->drawObject->tot_triangle_point + dm->drawObject->tot_loose_point);
case GPU_BUFFER_NORMAL:
return sizeof(float) * 3 * dm->drawObject->tot_triangle_point;
return sizeof(short) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point;
case GPU_BUFFER_COLOR:
return sizeof(char) * 3 * dm->drawObject->tot_triangle_point;
return sizeof(char) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point;
case GPU_BUFFER_UV:
return sizeof(float) * 2 * dm->drawObject->tot_triangle_point;
return sizeof(float) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point;
case GPU_BUFFER_UV_TEXPAINT:
return sizeof(float) * 4 * dm->drawObject->tot_triangle_point;
return sizeof(float) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point;
case GPU_BUFFER_EDGE:
return sizeof(int) * 2 * dm->drawObject->totedge;
return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->totedge;
case GPU_BUFFER_UVEDGE:
/* each face gets 3 points, 3 edges per triangle, and
* each edge has its own, non-shared coords, so each
* tri corner needs minimum of 4 floats, quads used
* less so here we can over allocate and assume all
* tris. */
return sizeof(float) * 4 * dm->drawObject->tot_triangle_point;
return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point;
case GPU_BUFFER_TRIANGLES:
return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point;
default:
return -1;
}
@ -1127,12 +616,9 @@ static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type)
/* call gpu_buffer_setup with settings for a particular type of buffer */
static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
{
const GPUBufferTypeSettings *ts;
void *user_data = NULL;
GPUBuffer *buf;
ts = &gpu_buffer_type_settings[type];
/* special handling for MCol and UV buffers */
if (type == GPU_BUFFER_COLOR) {
if (!(user_data = DM_get_tessface_data_layer(dm, dm->drawObject->colType)))
@ -1143,9 +629,7 @@ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
return NULL;
}
buf = gpu_buffer_setup(dm, dm->drawObject, ts->vector_size,
gpu_buffer_size_from_type(dm, type),
ts->gl_buffer_type, user_data, ts->copy);
buf = gpu_buffer_setup(dm, dm->drawObject, type, user_data);
return buf;
}
@ -1157,7 +641,7 @@ static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type)
GPUBuffer **buf;
if (!dm->drawObject)
dm->drawObject = GPU_drawobject_new(dm);
dm->drawObject = dm->gpuObjectNew(dm);
buf = gpu_drawobject_buffer_from_type(dm->drawObject, type);
if (!(*buf))
@ -1191,10 +675,10 @@ void GPU_normal_setup(DerivedMesh *dm)
glEnableClientState(GL_NORMAL_ARRAY);
if (dm->drawObject->normals->use_vbo) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id);
glNormalPointer(GL_FLOAT, 0, 0);
glNormalPointer(GL_SHORT, 4 * sizeof(short), 0);
}
else {
glNormalPointer(GL_FLOAT, 0, dm->drawObject->normals->pointer);
glNormalPointer(GL_SHORT, 4 * sizeof(short), dm->drawObject->normals->pointer);
}
GLStates |= GPU_BUFFER_NORMAL_STATE;
@ -1248,7 +732,7 @@ void GPU_color_setup(DerivedMesh *dm, int colType)
if (!dm->drawObject) {
/* XXX Not really nice, but we need a valid gpu draw object to set the colType...
* Else we would have to add a new param to gpu_buffer_setup_common. */
dm->drawObject = GPU_drawobject_new(dm);
dm->drawObject = dm->gpuObjectNew(dm);
dm->dirty &= ~DM_DIRTY_MCOL_UPDATE_DRAW;
dm->drawObject->colType = colType;
}
@ -1322,6 +806,18 @@ void GPU_uvedge_setup(DerivedMesh *dm)
GLStates |= GPU_BUFFER_VERTEX_STATE;
}
void GPU_triangle_setup(struct DerivedMesh *dm)
{
if (!gpu_buffer_setup_common(dm, GPU_BUFFER_TRIANGLES))
return;
if (dm->drawObject->triangles->use_vbo) {
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->triangles->id);
}
GLStates |= GPU_BUFFER_ELEMENT_STATE;
}
static int GPU_typesize(int type)
{
switch (type) {
@ -1352,7 +848,7 @@ int GPU_attrib_element_size(GPUAttrib data[], int numdata)
return elementsize;
}
void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata)
void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata, int element_size)
{
int i;
int elementsize;
@ -1366,7 +862,10 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
else
break;
}
elementsize = GPU_attrib_element_size(data, numdata);
if (element_size == 0)
elementsize = GPU_attrib_element_size(data, numdata);
else
elementsize = element_size;
if (buffer->use_vbo) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
@ -1390,6 +889,18 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
attribData[numdata].index = -1;
}
void GPU_interleaved_attrib_unbind(void)
{
int i;
for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
if (attribData[i].index != -1) {
glDisableVertexAttribArrayARB(attribData[i].index);
}
else
break;
}
attribData[0].index = -1;
}
void GPU_buffer_unbind(void)
{
@ -1492,6 +1003,7 @@ void GPU_buffer_unlock(GPUBuffer *buffer)
}
}
/* used for drawing edges */
void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count)
{
@ -1528,7 +1040,7 @@ typedef struct {
struct GPU_PBVH_Buffers {
/* opengl buffer handles */
GLuint vert_buf, index_buf;
GLuint vert_buf, index_buf, index_buf_fast;
GLenum index_type;
/* mesh pointers in case buffer allocation fails */
@ -2084,6 +1596,32 @@ static GLuint gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *to
return buffer;
}
#define FILL_FAST_BUFFER(type_) \
{ \
type_ *buffer; \
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \
sizeof(type_) * 6 * totgrid, NULL, \
GL_STATIC_DRAW_ARB); \
buffer = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); \
if (buffer) { \
int i; \
for (i = 0; i < totgrid; i++) { \
int currentquad = i * 6; \
buffer[currentquad] = i * gridsize * gridsize; \
buffer[currentquad + 1] = i * gridsize * gridsize + gridsize - 1; \
buffer[currentquad + 2] = (i + 1) * gridsize * gridsize - gridsize; \
buffer[currentquad + 3] = (i + 1) * gridsize * gridsize - 1; \
buffer[currentquad + 4] = i * gridsize * gridsize + gridsize - 1; \
buffer[currentquad + 5] = (i + 1) * gridsize * gridsize - gridsize; \
} \
glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); \
} \
else { \
glDeleteBuffersARB(1, &buffers->index_buf_fast); \
buffers->index_buf_fast = 0; \
} \
} (void)0
GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
BLI_bitmap **grid_hidden, int gridsize)
{
@ -2105,6 +1643,22 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
if (totquad == 0)
return buffers;
/* create and fill indices of the fast buffer too */
glGenBuffersARB(1, &buffers->index_buf_fast);
if (buffers->index_buf_fast) {
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf_fast);
if (totgrid * gridsize * gridsize < USHRT_MAX) {
FILL_FAST_BUFFER(unsigned short);
}
else {
FILL_FAST_BUFFER(unsigned int);
}
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
if (totquad == fully_visible_totquad) {
buffers->index_buf = gpu_get_grid_buffer(gridsize, &buffers->index_type, &buffers->tot_quad);
buffers->has_hidden = 0;
@ -2619,8 +2173,9 @@ static void gpu_draw_buffers_legacy_grids(GPU_PBVH_Buffers *buffers)
}
void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
bool wireframe)
bool wireframe, bool fast)
{
bool do_fast = fast && buffers->index_buf_fast;
/* sets material from the first face, to solve properly face would need to
* be sorted in buckets by materials */
if (setMaterial) {
@ -2651,7 +2206,9 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
if (buffers->index_buf)
if (do_fast)
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf_fast);
else if (buffers->index_buf)
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
if (wireframe)
@ -2668,7 +2225,10 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
offset + offsetof(VertexBufferFormat, color));
glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, 0);
if (do_fast)
glDrawElements(GL_TRIANGLES, buffers->totgrid * 6, buffers->index_type, 0);
else
glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, 0);
offset += buffers->gridkey.grid_area * sizeof(VertexBufferFormat);
}
@ -2797,6 +2357,8 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
gpu_pbvh_buffer_free_intern(buffers->vert_buf);
if (buffers->index_buf && (buffers->tot_tri || buffers->has_hidden))
gpu_pbvh_buffer_free_intern(buffers->index_buf);
if (buffers->index_buf_fast)
gpu_pbvh_buffer_free_intern(buffers->index_buf_fast);
MEM_freeN(buffers);
}