VBO offscreen selection drawing, cdderivedmesh

Get rid of legacy drawing, it's only used for selection,
    in which case we can prepare a temporary color buffer and draw
    at once. Code is not complete here because we still redundantly
    set the draw color in the draw function and don't ommit hidden
    faces automatically. Still it works 100% without immediate mode
    now.
This commit is contained in:
Antonis Ryakiotakis 2015-07-15 18:50:02 +02:00
parent 2daa4db8a0
commit 13c39e90b3
8 changed files with 166 additions and 199 deletions

View File

@ -149,6 +149,7 @@ typedef enum DMDrawFlag {
DM_DRAW_ALWAYS_SMOOTH = (1 << 1),
DM_DRAW_USE_ACTIVE_UV = (1 << 2),
DM_DRAW_USE_TEXPAINT_UV = (1 << 3),
DM_DRAW_SKIP_HIDDEN = (1 << 4),
} DMDrawFlag;
typedef enum DMForeachFlag {

View File

@ -60,6 +60,8 @@
#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "WM_api.h"
#include <string.h>
#include <limits.h>
#include <math.h>
@ -635,14 +637,15 @@ static void cdDM_drawMappedFaces(
void *userData, DMDrawFlag flag)
{
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
MVert *mv = cddm->mvert;
MFace *mf = cddm->mface;
MCol *mcol;
const float *nors = DM_get_tessface_data_layer(dm, CD_NORMAL);
const short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
int colType, useColors = flag & DM_DRAW_USE_COLORS;
int colType, useColors = flag & DM_DRAW_USE_COLORS, useHide = flag & DM_DRAW_SKIP_HIDDEN;
int i, orig;
int start_element = 0, tot_element, tot_drawn;
int totpoly;
int tottri;
int mat_index;
GPUBuffer *findex_buffer = NULL;
/* double lookup */
const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
@ -651,216 +654,153 @@ static void cdDM_drawMappedFaces(
index_mp_to_orig = NULL;
}
colType = CD_TEXTURE_MCOL;
mcol = DM_get_tessface_data_layer(dm, colType);
if (!mcol) {
colType = CD_PREVIEW_MCOL;
mcol = DM_get_tessface_data_layer(dm, colType);
}
if (!mcol) {
colType = CD_MCOL;
mcol = DM_get_tessface_data_layer(dm, colType);
}
cdDM_update_normals_from_pbvh(dm);
/* back-buffer always uses legacy since VBO's would need the
* color array temporarily overwritten for drawing, then reset. */
if (G.f & G_BACKBUFSEL) {
DEBUG_VBO("Using legacy code. cdDM_drawMappedFaces\n");
for (i = 0; i < dm->numTessFaceData; i++, mf++) {
int drawSmooth = ((flag & DM_DRAW_ALWAYS_SMOOTH) || lnors) ? 1 : (mf->flag & ME_SMOOTH);
DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
/* fist, setup common buffers */
GPU_vertex_setup(dm);
GPU_triangle_setup(dm);
orig = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i) : i;
if (orig == ORIGINDEX_NONE)
draw_option = setMaterial(mf->mat_nr + 1, NULL);
else if (setDrawOptions != NULL)
draw_option = setDrawOptions(userData, orig);
/* if we do selection, fill the selection buffer color */
if (G.f & G_BACKBUFSEL) {
Mesh *me = userData;
unsigned int *fi_map;
findex_buffer = GPU_buffer_alloc(dm->drawObject->tot_loop_verts * sizeof(int), false);
fi_map = GPU_buffer_lock(findex_buffer);
if (fi_map) {
for (i = 0; i < dm->numTessFaceData; i++, mf++) {
int selcol = 0xFFFFFFFF;
orig = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i) : i;
if ((orig != ORIGINDEX_NONE) && (!useHide || !(me->mpoly[orig].flag & ME_HIDE))) {
WM_framebuffer_index_get(orig + 1, &selcol);
}
fi_map[start_element++] = selcol;
fi_map[start_element++] = selcol;
fi_map[start_element++] = selcol;
if (mf->v4) {
fi_map[start_element++] = selcol;
}
}
start_element = 0;
mf = cddm->mface;
GPU_buffer_unlock(findex_buffer);
GPU_buffer_bind_as_color(findex_buffer);
}
}
else {
GPU_normal_setup(dm);
if (useColors) {
colType = CD_TEXTURE_MCOL;
mcol = DM_get_tessface_data_layer(dm, colType);
if (!mcol) {
colType = CD_PREVIEW_MCOL;
mcol = DM_get_tessface_data_layer(dm, colType);
}
if (!mcol) {
colType = CD_MCOL;
mcol = DM_get_tessface_data_layer(dm, colType);
}
if (useColors && mcol) {
GPU_color_setup(dm, colType);
}
}
}
glShadeModel(GL_SMOOTH);
tottri = dm->drawObject->tot_triangle_point;
if (tottri == 0) {
/* avoid buffer problems in following code */
}
else if (setDrawOptions == NULL) {
/* just draw the entire face array */
GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, 0, tottri);
}
else {
for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
int next_actualFace = bufmat->polys[0];
totpoly = bufmat->totpolys;
tot_element = 0;
start_element = 0;
tot_drawn = 0;
if (setMaterial)
draw_option = setMaterial(bufmat->mat_nr + 1, NULL);
if (draw_option != DM_DRAW_OPTION_SKIP) {
unsigned char *cp = NULL;
for (i = 0; i < totpoly; i++) {
int actualFace = next_actualFace;
int flush = 0;
draw_option = DM_DRAW_OPTION_NORMAL;
if (draw_option == DM_DRAW_OPTION_STIPPLE) {
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(stipple_quarttone);
}
if (i != totpoly - 1)
next_actualFace = bufmat->polys[i + 1];
if (useColors && mcol)
cp = (unsigned char *)&mcol[i * 4];
orig = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, actualFace) : actualFace;
/* no need to set shading mode to flat because
* normals are already used to change shading */
glShadeModel(GL_SMOOTH);
glBegin(mf->v4 ? GL_QUADS : GL_TRIANGLES);
if (setDrawOptions != NULL && (orig != ORIGINDEX_NONE))
draw_option = setDrawOptions(userData, orig);
if (lnors) {
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
glNormal3sv((const GLshort *)lnors[0][0]);
glVertex3fv(mv[mf->v1].co);
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
glNormal3sv((const GLshort *)lnors[0][1]);
glVertex3fv(mv[mf->v2].co);
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
glNormal3sv((const GLshort *)lnors[0][2]);
glVertex3fv(mv[mf->v3].co);
if (mf->v4) {
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
glNormal3sv((const GLshort *)lnors[0][3]);
glVertex3fv(mv[mf->v4].co);
if (draw_option == DM_DRAW_OPTION_STIPPLE) {
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(stipple_quarttone);
}
}
else if (!drawSmooth) {
if (nors) {
glNormal3fv(nors);
/* Goal is to draw as long of a contiguous triangle
* array as possible, so draw when we hit either an
* invisible triangle or at the end of the array */
/* flush buffer if current triangle isn't drawable or it's last triangle... */
flush = (ELEM(draw_option, DM_DRAW_OPTION_SKIP, DM_DRAW_OPTION_STIPPLE)) || (i == totpoly - 1);
if (!flush && compareDrawOptions) {
flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
}
tot_element += mf[actualFace].v4 ? 6 : 3;
if (flush) {
if (!ELEM(draw_option, DM_DRAW_OPTION_SKIP, DM_DRAW_OPTION_STIPPLE))
tot_drawn += mf[actualFace].v4 ? 6 : 3;
if (tot_drawn) {
GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
tot_drawn = 0;
}
start_element = tot_element;
if (draw_option == DM_DRAW_OPTION_STIPPLE)
glDisable(GL_POLYGON_STIPPLE);
}
else {
float nor[3];
if (mf->v4) {
normal_quad_v3(nor, mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
}
else {
normal_tri_v3(nor, mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
}
glNormal3fv(nor);
tot_drawn += mf[actualFace].v4 ? 6 : 3;
}
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
glVertex3fv(mv[mf->v1].co);
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
glVertex3fv(mv[mf->v2].co);
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
glVertex3fv(mv[mf->v3].co);
if (mf->v4) {
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
glVertex3fv(mv[mf->v4].co);
}
}
else {
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
glNormal3sv(mv[mf->v1].no);
glVertex3fv(mv[mf->v1].co);
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
glNormal3sv(mv[mf->v2].no);
glVertex3fv(mv[mf->v2].co);
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
glNormal3sv(mv[mf->v3].no);
glVertex3fv(mv[mf->v3].co);
if (mf->v4) {
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
glNormal3sv(mv[mf->v4].no);
glVertex3fv(mv[mf->v4].co);
}
}
glEnd();
if (draw_option == DM_DRAW_OPTION_STIPPLE)
glDisable(GL_POLYGON_STIPPLE);
}
if (nors)
nors += 3;
if (lnors)
lnors++;
}
}
else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
int start_element = 0, tot_element, tot_drawn;
int totpoly;
int tottri;
int mat_index;
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
if (useColors && mcol) {
GPU_color_setup(dm, colType);
}
glShadeModel(GL_SMOOTH);
tottri = dm->drawObject->tot_triangle_point;
if (tottri == 0) {
/* avoid buffer problems in following code */
}
else if (setDrawOptions == NULL) {
/* just draw the entire face array */
GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, 0, tottri);
}
else {
for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
int next_actualFace = bufmat->polys[0];
totpoly = bufmat->totpolys;
tot_element = 0;
tot_drawn = 0;
start_element = 0;
if (setMaterial)
draw_option = setMaterial(bufmat->mat_nr + 1, NULL);
if (draw_option != DM_DRAW_OPTION_SKIP) {
for (i = 0; i < totpoly; i++) {
//int actualFace = dm->drawObject->triangle_to_mface[i];
int actualFace = next_actualFace;
int flush = 0;
draw_option = DM_DRAW_OPTION_NORMAL;
if (i != totpoly - 1)
next_actualFace = bufmat->polys[i + 1];
orig = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, actualFace) : actualFace;
if (setDrawOptions != NULL && (orig != ORIGINDEX_NONE))
draw_option = setDrawOptions(userData, orig);
if (draw_option == DM_DRAW_OPTION_STIPPLE) {
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(stipple_quarttone);
}
/* Goal is to draw as long of a contiguous triangle
* array as possible, so draw when we hit either an
* invisible triangle or at the end of the array */
/* flush buffer if current triangle isn't drawable or it's last triangle... */
flush = (ELEM(draw_option, DM_DRAW_OPTION_SKIP, DM_DRAW_OPTION_STIPPLE)) || (i == totpoly - 1);
if (!flush && compareDrawOptions) {
flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
}
tot_element += mf[actualFace].v4 ? 6 : 3;
if (flush) {
if (!ELEM(draw_option, DM_DRAW_OPTION_SKIP, DM_DRAW_OPTION_STIPPLE))
tot_drawn += mf[actualFace].v4 ? 6 : 3;
if (tot_drawn) {
GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
tot_drawn = 0;
}
start_element = tot_element;
if (draw_option == DM_DRAW_OPTION_STIPPLE)
glDisable(GL_POLYGON_STIPPLE);
}
else {
tot_drawn += mf[actualFace].v4 ? 6 : 3;
}
}
glShadeModel(GL_FLAT);
}
}
}
GPU_buffer_unbind();
}
glShadeModel(GL_FLAT);
GPU_buffer_unbind();
if (G.f & G_BACKBUFSEL)
GPU_buffer_free(findex_buffer);
}
static void cdDM_drawMappedFacesTex(

View File

@ -8531,7 +8531,7 @@ static void bbs_mesh_solid_faces(Scene *scene, Object *ob)
DM_update_materials(dm, ob);
if ((me->editflag & ME_EDIT_PAINT_FACE_SEL))
dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, NULL, NULL, me, 0);
dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, NULL, NULL, me, DM_DRAW_SKIP_HIDDEN);
else
dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, NULL, NULL, me, 0);

View File

@ -172,6 +172,7 @@ void GPU_uv_setup(struct DerivedMesh *dm);
void GPU_texpaint_uv_setup(struct DerivedMesh *dm);
/* colType is the cddata MCol type to use! */
void GPU_color_setup(struct DerivedMesh *dm, int colType);
void GPU_buffer_bind_as_color(GPUBuffer *buffer);
void GPU_edge_setup(struct DerivedMesh *dm); /* does not mix with other data */
void GPU_uvedge_setup(struct DerivedMesh *dm);

View File

@ -764,6 +764,21 @@ void GPU_color_setup(DerivedMesh *dm, int colType)
GLStates |= GPU_BUFFER_COLOR_STATE;
}
void GPU_buffer_bind_as_color(GPUBuffer *buffer)
{
glEnableClientState(GL_COLOR_ARRAY);
if (buffer->use_vbo) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);
}
else {
glColorPointer(4, GL_UNSIGNED_BYTE, 0, buffer->pointer);
}
GLStates |= GPU_BUFFER_COLOR_STATE;
}
void GPU_edge_setup(DerivedMesh *dm)
{
if (!gpu_buffer_setup_common(dm, GPU_BUFFER_EDGE))

View File

@ -392,6 +392,7 @@ void wmOrtho2_pixelspace(const float x, const float y);
/* utilities */
void WM_framebuffer_index_set(int index);
void WM_framebuffer_index_get(int index, int *r_col);
int WM_framebuffer_to_index(unsigned int col);
void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size);

View File

@ -459,6 +459,13 @@ void WM_framebuffer_index_set(int index)
cpack(col);
}
void WM_framebuffer_index_get(int index, int *r_col)
{
*r_col = index_to_framebuffer(index);
}
#define INDEX_FROM_BUF_8(col) (((col & 0xC00000) >> 18) + ((col & 0xC000) >> 12) + ((col & 0xC0) >> 6))
#define INDEX_FROM_BUF_12(col) (((col & 0xF00000) >> 12) + ((col & 0xF000) >> 8) + ((col & 0xF0) >> 4))
#define INDEX_FROM_BUF_15_16(col) (((col & 0xF80000) >> 9) + ((col & 0xF800) >> 6) + ((col & 0xF8) >> 3))

View File

@ -316,6 +316,8 @@ bool WM_uilisttype_add(struct uiListType *ult) RET_ZERO
void WM_uilisttype_freelink(struct uiListType *ult) RET_NONE
void WM_uilisttype_free(void) RET_NONE
void WM_framebuffer_index_get(int index, int *r_col) RET_NONE
struct wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id) RET_NULL
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event) RET_ZERO
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) RET_NONE