diff options
-rw-r--r-- | source/blender/blenkernel/BKE_DerivedMesh.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_pbvh.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cdderivedmesh.c | 1187 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pbvh.c | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subsurf_ccg.c | 813 | ||||
-rw-r--r-- | source/blender/gpu/GPU_buffers.h | 56 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 746 |
7 files changed, 1635 insertions, 1180 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 984147de3af..881b233dc3c 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -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); diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 0832e2498d4..fbaf91d60bd 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -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 { diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 37c3376ecdb..475233206f8 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -341,8 +341,8 @@ static void cdDM_update_normals_from_pbvh(DerivedMesh *dm) static void cdDM_drawVerts(DerivedMesh *dm) { GPU_vertex_setup(dm); - if (dm->drawObject->tot_triangle_point) - glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_triangle_point); + if (dm->drawObject->tot_loop_verts) + glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loop_verts); else glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loose_point); GPU_buffer_unbind(); @@ -391,7 +391,7 @@ static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdg if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { - BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, true); + BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, true, false); return; } @@ -442,7 +442,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL); BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, - setMaterial, false); + setMaterial, false, false); glShadeModel(GL_FLAT); } @@ -451,11 +451,11 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, 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)) { - glDrawArrays(GL_TRIANGLES, dm->drawObject->materials[a].start, - dm->drawObject->materials[a].totpoint); + GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements); } } GPU_buffer_unbind(); @@ -473,12 +473,13 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, const MFace *mf = DM_get_tessface_data_layer(dm, CD_MFACE); MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY); MCol *mcol; - int i; - int colType, startFace = 0; + int i, orig; + int colType, start_element; bool use_tface = (uvflag & DM_DRAW_USE_ACTIVE_UV) != 0; - int tottri; + int totpoly; int next_actualFace; - + int mat_index; + int tot_element; /* double lookup */ const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); @@ -497,7 +498,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { if (BKE_pbvh_has_faces(cddm->pbvh)) { GPU_set_tpage(NULL, false, false); - BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false); + BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false); } return; @@ -518,6 +519,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, GPU_vertex_setup(dm); GPU_normal_setup(dm); + GPU_triangle_setup(dm); if (uvflag & DM_DRAW_USE_TEXPAINT_UV) GPU_texpaint_uv_setup(dm); else @@ -525,76 +527,84 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, if (mcol) { GPU_color_setup(dm, colType); } - - tottri = dm->drawObject->tot_triangle_point / 3; - next_actualFace = dm->drawObject->triangle_to_mface[0]; - + glShadeModel(GL_SMOOTH); /* lastFlag = 0; */ /* UNUSED */ - for (i = 0; i < tottri; i++) { - int actualFace = next_actualFace; - DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; - int flush = 0; - - if (i != tottri - 1) - next_actualFace = dm->drawObject->triangle_to_mface[i + 1]; - - if (drawParams) { - MTexPoly *tp = NULL; - if (use_tface && mtexpoly && index_mf_to_mpoly) { - int actualFace_poly = index_mf_to_mpoly[actualFace]; - if (actualFace_poly != ORIGINDEX_NONE) { - tp = &mtexpoly[actualFace_poly]; + 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; + + tot_element = 0; + start_element = bufmat->start; + + for (i = 0; i < totpoly; i++) { + int actualFace = bufmat->polys[i]; + DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; + int flush = 0; + + if (i != totpoly - 1) + next_actualFace = bufmat->polys[i + 1]; + + if (drawParams) { + MTexPoly *tp = NULL; + if (use_tface && mtexpoly && index_mf_to_mpoly) { + int actualFace_poly = index_mf_to_mpoly[actualFace]; + if (actualFace_poly != ORIGINDEX_NONE) { + tp = &mtexpoly[actualFace_poly]; + } } - } - draw_option = drawParams(tp, (mcol != NULL), mf[actualFace].mat_nr); - } - else { - if (index_mf_to_mpoly) { - const int orig = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, actualFace); - if (orig == ORIGINDEX_NONE) { - /* XXX, this is not really correct - * it will draw the previous faces context for this one when we don't know its settings. - * but better then skipping it altogether. - campbell */ - draw_option = DM_DRAW_OPTION_NORMAL; + draw_option = drawParams(tp, (mcol != NULL), mf[actualFace].mat_nr); + } + else { + if (index_mf_to_mpoly) { + orig = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, actualFace); + if (orig == ORIGINDEX_NONE) { + /* XXX, this is not really correct + * it will draw the previous faces context for this one when we don't know its settings. + * but better then skipping it altogether. - campbell */ + draw_option = DM_DRAW_OPTION_NORMAL; + } + else if (drawParamsMapped) { + draw_option = drawParamsMapped(userData, orig, mf[actualFace].mat_nr); + } } else if (drawParamsMapped) { - draw_option = drawParamsMapped(userData, orig, mf[actualFace].mat_nr); + draw_option = drawParamsMapped(userData, actualFace, mf[actualFace].mat_nr); } } - else if (drawParamsMapped) { - draw_option = drawParamsMapped(userData, actualFace, mf[actualFace].mat_nr); + + /* 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; } - } - - /* flush buffer if current triangle isn't drawable or it's last triangle */ - flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == tottri - 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) { - int first = startFace * 3; - /* Add one to the length if we're drawing at the end of the array */ - int count = (i - startFace + (draw_option != DM_DRAW_OPTION_SKIP ? 1 : 0)) * 3; - - if (count) { - if (mcol && draw_option != DM_DRAW_OPTION_NO_MCOL) - GPU_color_switch(1); - else - GPU_color_switch(0); - - glDrawArrays(GL_TRIANGLES, first, count); + + if (flush) { + if (draw_option != DM_DRAW_OPTION_SKIP) + tot_element += mf[actualFace].v4 ? 6 : 3; + + 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 += mf[actualFace].v4 ? 6 : 3; } - - startFace = i + 1; } } - + GPU_buffer_unbind(); glShadeModel(GL_FLAT); @@ -747,87 +757,92 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, } } else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */ - int prevstart = 0; + int start_element = 0, tot_element; + 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); } - tottri = dm->drawObject->tot_triangle_point / 3; glShadeModel(GL_SMOOTH); + tottri = dm->drawObject->tot_triangle_point / 3; + if (tottri == 0) { /* avoid buffer problems in following code */ } else if (setDrawOptions == NULL) { /* just draw the entire face array */ - glDrawArrays(GL_TRIANGLES, 0, (tottri) * 3); + GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, 0, 3 * tottri); } - else { - /* we need to check if the next material changes */ - int next_actualFace = dm->drawObject->triangle_to_mface[0]; - short prev_mat_nr = -1; - - for (i = 0; i < tottri; i++) { - //int actualFace = dm->drawObject->triangle_to_mface[i]; - int actualFace = next_actualFace; - MFace *mface = mf + actualFace; - /*int drawSmooth = (flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : (mface->flag & ME_SMOOTH);*/ /* UNUSED */ + 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 flush = 0; - - if (i != tottri - 1) - next_actualFace = dm->drawObject->triangle_to_mface[i + 1]; - - orig = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, actualFace) : actualFace; - - if (mface->mat_nr != prev_mat_nr) { - if (setMaterial) - draw_option = setMaterial(mface->mat_nr + 1, NULL); - - prev_mat_nr = mface->mat_nr; - } - - 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 + int next_actualFace = bufmat->polys[0]; + totpoly = bufmat->totpolys; + + tot_element = 0; + start_element = bufmat->start; + + 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 == tottri - 1); - - /* ... or when material setting is dissferent */ - flush |= mf[actualFace].mat_nr != mf[next_actualFace].mat_nr; - - if (!flush && compareDrawOptions) { - flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; - } - - if (flush) { - int first = prevstart * 3; - /* Add one to the length if we're drawing at the end of the array */ - int count = (i - prevstart + (draw_option != DM_DRAW_OPTION_SKIP ? 1 : 0)) * 3; - - if (count) - glDrawArrays(GL_TRIANGLES, first, count); - - prevstart = i + 1; - - if (draw_option == DM_DRAW_OPTION_STIPPLE) - glDisable(GL_POLYGON_STIPPLE); + + /* 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; + } + + if (flush) { + if (!ELEM(draw_option, DM_DRAW_OPTION_SKIP, DM_DRAW_OPTION_STIPPLE)) + tot_element += mf[actualFace].v4 ? 6 : 3; + + if (tot_element) + GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, start_element, tot_element); + + start_element = tot_element; + + if (draw_option == DM_DRAW_OPTION_STIPPLE) + glDisable(GL_POLYGON_STIPPLE); + } + else { + tot_element += mf[actualFace].v4 ? 6 : 3; + } + } + + glShadeModel(GL_FLAT); } } - - glShadeModel(GL_FLAT); } GPU_buffer_unbind(); } @@ -858,6 +873,13 @@ static void cddm_draw_attrib_vertex(DMVertexAttribs *attribs, const MVert *mvert glVertex3fv(mvert[index].co); } +typedef struct { + DMVertexAttribs attribs; + int numdata; + + GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/ +} GPUMaterialConv; + static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial, DMSetDrawOptions setDrawOptions, @@ -865,7 +887,6 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, { CDDerivedMesh *cddm = (CDDerivedMesh *) dm; GPUVertexAttribs gattribs; - DMVertexAttribs attribs; const MVert *mvert = cddm->mvert; const MFace *mface = cddm->mface; /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */ @@ -889,7 +910,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { if (BKE_pbvh_has_faces(cddm->pbvh)) { setMaterial(1, &gattribs); - BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false); + BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false); } return; @@ -906,6 +927,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, if ((GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_MAC, GPU_DRIVER_ANY) && (U.gameflags & USER_DISABLE_VBO)) || setDrawOptions != NULL) { + DMVertexAttribs attribs; DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n"); memset(&attribs, 0, sizeof(attribs)); @@ -914,7 +936,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, for (a = 0; a < dm->numTessFaceData; a++, mface++) { const bool smoothnormal = lnors || (mface->flag & ME_SMOOTH); const short (*ln1)[3] = NULL, (*ln2)[3] = NULL, (*ln3)[3] = NULL, (*ln4)[3] = NULL; - new_matnr = mface->mat_nr + 1; + new_matnr = mface->mat_nr; if (new_matnr != matnr) { glEnd(); @@ -977,214 +999,190 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, glEnd(); } else { + GPUMaterialConv *matconv; + int offset; + int totface = dm->getNumTessFaces(dm); + int *mat_orig_to_new; + int tot_active_mat; GPUBuffer *buffer = NULL; - char *varray = NULL; - int numdata = 0, elementsize = 0, offset; - int start = 0, numfaces = 0 /* , prevdraw = 0 */ /* UNUSED */, curface = 0; - int i; + char *varray; + int max_element_size = 0; + int tot_loops = 0; const MFace *mf = mface; - GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/ - memset(&attribs, 0, sizeof(attribs)); GPU_vertex_setup(dm); GPU_normal_setup(dm); - - for (i = 0; i < dm->drawObject->tot_triangle_point / 3; i++) { - - a = dm->drawObject->triangle_to_mface[i]; - - mface = mf + a; - new_matnr = mface->mat_nr + 1; - - if (new_matnr != matnr) { - numfaces = curface - start; - if (numfaces > 0) { - - if (do_draw) { - - if (numdata != 0) { - - GPU_buffer_unlock(buffer); - - GPU_interleaved_attrib_setup(buffer, datatypes, numdata); - } - - glDrawArrays(GL_TRIANGLES, start * 3, numfaces * 3); - - if (numdata != 0) { - - GPU_buffer_free(buffer); - - buffer = NULL; - } - - } + GPU_triangle_setup(dm); + + tot_active_mat = dm->drawObject->totmaterial; + + matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat, + "cdDM_drawMappedFacesGLSL.matconv"); + mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat, + "cdDM_drawMappedFacesGLSL.mat_orig_to_new"); + + /* part one, check what attributes are needed per material */ + for (a = 0; a < tot_active_mat; a++) { + new_matnr = dm->drawObject->materials[a].mat_nr; + + /* map from original material index to new + * GPUBufferMaterial index */ + mat_orig_to_new[new_matnr] = a; + do_draw = setMaterial(new_matnr + 1, &gattribs); + + if (do_draw) { + int numdata = 0; + DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs); + + if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) { + matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index; + matconv[a].datatypes[numdata].size = 3; + matconv[a].datatypes[numdata].type = GL_FLOAT; + numdata++; } - numdata = 0; - start = curface; - /* prevdraw = do_draw; */ /* UNUSED */ - do_draw = setMaterial(matnr = new_matnr, &gattribs); - if (do_draw) { - DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); - - if (attribs.totorco && attribs.orco.array) { - datatypes[numdata].index = attribs.orco.gl_index; - datatypes[numdata].size = 3; - datatypes[numdata].type = GL_FLOAT; + for (b = 0; b < matconv[a].attribs.tottface; b++) { + if (matconv[a].attribs.tface[b].array) { + matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index; + matconv[a].datatypes[numdata].size = 2; + matconv[a].datatypes[numdata].type = GL_FLOAT; numdata++; } - for (b = 0; b < attribs.tottface; b++) { - if (attribs.tface[b].array) { - datatypes[numdata].index = attribs.tface[b].gl_index; - datatypes[numdata].size = 2; - datatypes[numdata].type = GL_FLOAT; - numdata++; - } - } - for (b = 0; b < attribs.totmcol; b++) { - if (attribs.mcol[b].array) { - datatypes[numdata].index = attribs.mcol[b].gl_index; - datatypes[numdata].size = 4; - datatypes[numdata].type = GL_UNSIGNED_BYTE; - numdata++; - } - } - if (attribs.tottang && attribs.tang.array) { - datatypes[numdata].index = attribs.tang.gl_index; - datatypes[numdata].size = 4; - datatypes[numdata].type = GL_FLOAT; - numdata++; - } - if (numdata != 0) { - elementsize = GPU_attrib_element_size(datatypes, numdata); - buffer = GPU_buffer_alloc(elementsize * dm->drawObject->tot_triangle_point, false); - if (buffer == NULL) { - buffer = GPU_buffer_alloc(elementsize * dm->drawObject->tot_triangle_point, true); - } - varray = GPU_buffer_lock_stream(buffer); - if (varray == NULL) { - GPU_buffer_unbind(); - GPU_buffer_free(buffer); - fprintf(stderr, "Out of memory, can't draw object\n"); - return; - } - } - else { - /* if the buffer was set, don't use it again. - * prevdraw was assumed true but didnt run so set to false - [#21036] */ - /* prevdraw = 0; */ /* UNUSED */ - buffer = NULL; - } - } - } - - if (do_draw && numdata != 0) { - offset = 0; - if (attribs.totorco && attribs.orco.array) { - copy_v3_v3((float *)&varray[elementsize * curface * 3], (float *)attribs.orco.array[mface->v1]); - copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize], (float *)attribs.orco.array[mface->v2]); - copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize * 2], (float *)attribs.orco.array[mface->v3]); - offset += sizeof(float) * 3; } - for (b = 0; b < attribs.tottface; b++) { - if (attribs.tface[b].array) { - MTFace *tf = &attribs.tface[b].array[a]; - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset], tf->uv[0]); - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize], tf->uv[1]); - - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tf->uv[2]); - offset += sizeof(float) * 2; + for (b = 0; b < matconv[a].attribs.totmcol; b++) { + if (matconv[a].attribs.mcol[b].array) { + matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index; + matconv[a].datatypes[numdata].size = 4; + matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE; + numdata++; } } - for (b = 0; b < attribs.totmcol; b++) { - if (attribs.mcol[b].array) { - MCol *cp = &attribs.mcol[b].array[a * 4 + 0]; - GLubyte col[4]; - col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; - copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset], (char *)col); - cp = &attribs.mcol[b].array[a * 4 + 1]; - col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; - copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset + elementsize], (char *)col); - cp = &attribs.mcol[b].array[a * 4 + 2]; - col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; - copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset + elementsize * 2], (char *)col); - offset += sizeof(unsigned char) * 4; - } + if (matconv[a].attribs.tottang && matconv[a].attribs.tang.array) { + matconv[a].datatypes[numdata].index = matconv[a].attribs.tang.gl_index; + matconv[a].datatypes[numdata].size = 4; + matconv[a].datatypes[numdata].type = GL_FLOAT; + numdata++; } - if (attribs.tottang && attribs.tang.array) { - const float *tang = attribs.tang.array[a * 4 + 0]; - copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset], tang); - tang = attribs.tang.array[a * 4 + 1]; - copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset + elementsize], tang); - tang = attribs.tang.array[a * 4 + 2]; - copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tang); - offset += sizeof(float) * 4; + if (numdata != 0) { + matconv[a].numdata = numdata; + max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size); } - (void)offset; } - curface++; - if (mface->v4) { - if (do_draw && numdata != 0) { - offset = 0; - if (attribs.totorco && attribs.orco.array) { - copy_v3_v3((float *)&varray[elementsize * curface * 3], (float *)attribs.orco.array[mface->v3]); - copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize], (float *)attribs.orco.array[mface->v4]); - copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize * 2], (float *)attribs.orco.array[mface->v1]); + } + + /* part two, generate and fill the arrays with the data */ + if (max_element_size > 0) { + buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts, false); + + if (buffer == NULL) { + buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts, true); + } + varray = GPU_buffer_lock_stream(buffer); + if (varray == NULL) { + GPU_buffer_unbind(); + GPU_buffer_free(buffer); + MEM_freeN(mat_orig_to_new); + MEM_freeN(matconv); + fprintf(stderr, "Out of memory, can't draw object\n"); + return; + } + + mface = mf; + + for (a = 0; a < totface; a++, mface++) { + int i = mat_orig_to_new[mface->mat_nr]; + offset = tot_loops * max_element_size; + + if (matconv[i].numdata != 0) { + if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) { + copy_v3_v3((float *)&varray[offset], (float *)matconv[i].attribs.orco.array[mface->v1]); + copy_v3_v3((float *)&varray[offset + max_element_size], (float *)matconv[i].attribs.orco.array[mface->v2]); + copy_v3_v3((float *)&varray[offset + max_element_size * 2], (float *)matconv[i].attribs.orco.array[mface->v3]); + if (mface->v4) { + copy_v3_v3((float *)&varray[offset + max_element_size * 3], (float *)matconv[i].attribs.orco.array[mface->v4]); + } offset += sizeof(float) * 3; } - for (b = 0; b < attribs.tottface; b++) { - if (attribs.tface[b].array) { - MTFace *tf = &attribs.tface[b].array[a]; - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset], tf->uv[2]); - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize], tf->uv[3]); - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tf->uv[0]); + for (b = 0; b < matconv[i].attribs.tottface; b++) { + if (matconv[i].attribs.tface[b].array) { + MTFace *tf = &matconv[i].attribs.tface[b].array[a]; + copy_v2_v2((float *)&varray[offset], tf->uv[0]); + copy_v2_v2((float *)&varray[offset + max_element_size], tf->uv[1]); + copy_v2_v2((float *)&varray[offset + max_element_size * 2], tf->uv[2]); + if (mface->v4) { + copy_v2_v2((float *)&varray[offset + max_element_size * 3], tf->uv[3]); + } offset += sizeof(float) * 2; } } - for (b = 0; b < attribs.totmcol; b++) { - if (attribs.mcol[b].array) { - MCol *cp = &attribs.mcol[b].array[a * 4 + 2]; + for (b = 0; b < matconv[i].attribs.totmcol; b++) { + if (matconv[i].attribs.mcol[b].array) { + MCol *cp = &matconv[i].attribs.mcol[b].array[a * 4 + 0]; GLubyte col[4]; col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; - copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset], (char *)col); - cp = &attribs.mcol[b].array[a * 4 + 3]; + copy_v4_v4_char((char *)&varray[offset], (char *)col); + cp = &matconv[i].attribs.mcol[b].array[a * 4 + 1]; col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; - copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset + elementsize], (char *)col); - cp = &attribs.mcol[b].array[a * 4 + 0]; + copy_v4_v4_char((char *)&varray[offset + max_element_size], (char *)col); + cp = &matconv[i].attribs.mcol[b].array[a * 4 + 2]; col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; - copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset + elementsize * 2], (char *)col); + copy_v4_v4_char((char *)&varray[offset + max_element_size * 2], (char *)col); + if (mface->v4) { + cp = &matconv[i].attribs.mcol[b].array[a * 4 + 3]; + col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; + copy_v4_v4_char((char *)&varray[offset + max_element_size * 3], (char *)col); + } offset += sizeof(unsigned char) * 4; } } - if (attribs.tottang && attribs.tang.array) { - const float *tang = attribs.tang.array[a * 4 + 2]; - copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset], tang); - tang = attribs.tang.array[a * 4 + 3]; - copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset + elementsize], tang); - tang = attribs.tang.array[a * 4 + 0]; - copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tang); + if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) { + const float *tang = matconv[i].attribs.tang.array[a * 4 + 0]; + copy_v4_v4((float *)&varray[offset], tang); + tang = matconv[i].attribs.tang.array[a * 4 + 1]; + copy_v4_v4((float *)&varray[offset + max_element_size], tang); + tang = matconv[i].attribs.tang.array[a * 4 + 2]; + copy_v4_v4((float *)&varray[offset + max_element_size * 2], tang); + if (mface->v4) { + tang = matconv[i].attribs.tang.array[a * 4 + 3]; + copy_v4_v4((float *)&varray[offset + max_element_size * 3], tang); + } offset += sizeof(float) * 4; } - (void)offset; } - curface++; - i++; + + if (mface->v4) { + tot_loops += 4; + } + else { + tot_loops += 3; + } } + GPU_buffer_unlock(buffer); } - numfaces = curface - start; - if (numfaces > 0) { + + for (a = 0; a < tot_active_mat; a++) { + new_matnr = dm->drawObject->materials[a].mat_nr; + + do_draw = setMaterial(new_matnr + 1, &gattribs); + if (do_draw) { - if (numdata != 0) { - GPU_buffer_unlock(buffer); - GPU_interleaved_attrib_setup(buffer, datatypes, numdata); + if (matconv[a].numdata) { + GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size); + } + GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, + dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements); + if (matconv[a].numdata) { + GPU_interleaved_attrib_unbind(); } - glDrawArrays(GL_TRIANGLES, start * 3, (curface - start) * 3); } } + GPU_buffer_unbind(); - - GPU_buffer_free(buffer); + if (buffer) + GPU_buffer_free(buffer); + + MEM_freeN(mat_orig_to_new); + MEM_freeN(matconv); } glShadeModel(GL_FLAT); @@ -1223,7 +1221,7 @@ static void cdDM_drawMappedFacesMat(DerivedMesh *dm, if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { if (BKE_pbvh_has_faces(cddm->pbvh)) { setMaterial(userData, 1, &gattribs); - BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false); + BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false); } return; @@ -1326,6 +1324,582 @@ static void cdDM_drawMappedEdges(DerivedMesh *dm, DMSetDrawOptions setDrawOption glEnd(); } +static void cdDM_buffer_copy_triangles(DerivedMesh *dm, float *varray_, int *mat_orig_to_new, void *UNUSED(user)) +{ + GPUBufferMaterial *gpumat; + MFace *f; + int i, start, totface, findex = 0; + unsigned int *varray = (unsigned int *)varray_; + + f = dm->getTessFaceArray(dm); + + totface = dm->getNumTessFaces(dm); + for (i = 0; i < totface; i++, f++) { + gpumat = dm->drawObject->materials + mat_orig_to_new[f->mat_nr]; + start = gpumat->counter; + + /* v1 v2 v3 */ + varray[start++] = findex; + varray[start++] = findex + 1; + varray[start++] = findex + 2; + + if (f->v4) { + /* v3 v4 v1 */ + varray[start++] = findex + 2; + varray[start++] = findex + 3; + varray[start++] = findex; + + gpumat->counter += 6; + findex += 4; + } + else { + gpumat->counter += 3; + findex += 3; + } + } +} + +static void cdDM_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *UNUSED(mat_orig_to_new), void *UNUSED(user)) +{ + MVert *mvert; + MFace *f; + int i, j, start, totface; + + mvert = dm->getVertArray(dm); + f = dm->getTessFaceArray(dm); + + start = 0; + totface = dm->getNumTessFaces(dm); + for (i = 0; i < totface; i++, f++) { + /* 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); + start += 9; + + if (f->v4) { + /* v4 */ + copy_v3_v3(&varray[start], mvert[f->v4].co); + start += 3; + } + } + + /* 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 cdDM_buffer_copy_normal(DerivedMesh *dm, float *varray_, int *UNUSED(mat_orig_to_new), void *UNUSED(user)) +{ + int i, totface; + int start; + float f_no[3]; + + short *varray = (short *)varray_; + const float *nors = dm->getTessFaceDataArray(dm, CD_NORMAL); + short (*tlnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL); + MVert *mvert = dm->getVertArray(dm); + MFace *f = dm->getTessFaceArray(dm); + + totface = dm->getNumTessFaces(dm); + start = 0; + for (i = 0; i < totface; i++, f++) { + const int smoothnormal = (f->flag & ME_SMOOTH); + + if (tlnors) { + short (*tlnor)[3] = tlnors[i]; + /* Copy loop normals */ + copy_v3_v3_short(&varray[start], tlnor[0]); + copy_v3_v3_short(&varray[start + 3], tlnor[1]); + copy_v3_v3_short(&varray[start + 6], tlnor[2]); + start += 9; + + if (f->v4) { + copy_v3_v3_short(&varray[start], tlnor[3]); + start += 3; + } + } + else if (smoothnormal) { + /* copy vertex normal */ + copy_v3_v3_short(&varray[start], mvert[f->v1].no); + copy_v3_v3_short(&varray[start + 4], mvert[f->v2].no); + copy_v3_v3_short(&varray[start + 8], mvert[f->v3].no); + start += 12; + + if (f->v4) { + copy_v3_v3_short(&varray[start], mvert[f->v4].no); + start += 4; + } + } + else if (nors) { + /* copy cached face normal */ + normal_float_to_short_v3(&varray[start], &nors[i * 3]); + normal_float_to_short_v3(&varray[start + 4], &nors[i * 3]); + normal_float_to_short_v3(&varray[start + 8], &nors[i * 3]); + start += 12; + + if (f->v4) { + normal_float_to_short_v3(&varray[start], &nors[i * 3]); + start += 4; + } + } + 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); + + normal_float_to_short_v3(&varray[start], f_no); + normal_float_to_short_v3(&varray[start + 4], f_no); + normal_float_to_short_v3(&varray[start + 8], f_no); + start += 12; + + if (f->v4) { + normal_float_to_short_v3(&varray[start], f_no); + start += 4; + } + } + } +} + +static void cdDM_buffer_copy_uv(DerivedMesh *dm, float *varray, int *UNUSED(mat_orig_to_new), void *UNUSED(user)) +{ + int start; + int i, totface; + + MTFace *mtface; + MFace *f; + + if (!(mtface = DM_get_tessface_data_layer(dm, CD_MTFACE))) + return; + f = dm->getTessFaceArray(dm); + + start = 0; + totface = dm->getNumTessFaces(dm); + for (i = 0; i < totface; i++, f++) { + /* 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]); + start += 6; + + if (f->v4) { + /* v4 */ + copy_v2_v2(&varray[start], mtface[i].uv[3]); + start += 2; + } + } +} + + +static void cdDM_buffer_copy_uv_texpaint(DerivedMesh *dm, float *varray, int *UNUSED(mat_orig_to_new), void *UNUSED(user)) +{ + int start; + int i, totface; + + int totmaterial = dm->totmat; + MTFace **mtface_base; + MTFace *stencil_base; + int stencil; + 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); + start = 0; + + for (i = 0; i < totface; i++, mf++) { + int mat_i = mf->mat_nr; + + /* 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]); + start += 12; + + if (mf->v4) { + /* v4 */ + copy_v2_v2(&varray[start], mtface_base[mat_i][i].uv[3]); + copy_v2_v2(&varray[start + 2], stencil_base[i].uv[3]); + start += 4; + } + } + + 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 cdDM_buffer_copy_mcol(DerivedMesh *dm, float *varray_, int *UNUSED(mat_orig_to_new), void *user) +{ + int i, totface, start; + unsigned char *varray = (unsigned char *)varray_; + unsigned char *mcol = (unsigned char *)user; + MFace *f = dm->getTessFaceArray(dm); + + totface = dm->getNumTessFaces(dm); + start = 0; + for (i = 0; i < totface; i++, f++) { + /* 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]); + start += 9; + + if (f->v4) { + /* v3 v4 v1 */ + copy_mcol_uc3(&varray[start], &mcol[i * 16 + 12]); + start += 3; + } + } +} + +static void cdDM_buffer_copy_edge(DerivedMesh *dm, float *varray_, int *UNUSED(mat_orig_to_new), void *UNUSED(user)) +{ + 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 cdDM_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(mat_orig_to_new), void *UNUSED(user)) +{ + 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; + } + } +} + +static void cdDM_copy_gpu_data(DerivedMesh *dm, int type, float *varray, + int *mat_orig_to_new, void *user_data) +{ + switch(type) { + case GPU_BUFFER_VERTEX: + cdDM_buffer_copy_vertex(dm, varray, mat_orig_to_new, user_data); + break; + case GPU_BUFFER_NORMAL: + cdDM_buffer_copy_normal(dm, varray, mat_orig_to_new, user_data); + break; + case GPU_BUFFER_COLOR: + cdDM_buffer_copy_mcol(dm, varray, mat_orig_to_new, user_data); + break; + case GPU_BUFFER_UV: + cdDM_buffer_copy_uv(dm, varray, mat_orig_to_new, user_data); + break; + case GPU_BUFFER_UV_TEXPAINT: + cdDM_buffer_copy_uv_texpaint(dm, varray, mat_orig_to_new, user_data); + break; + case GPU_BUFFER_EDGE: + cdDM_buffer_copy_edge(dm, varray, mat_orig_to_new, user_data); + break; + case GPU_BUFFER_UVEDGE: + cdDM_buffer_copy_uvedge(dm, varray, mat_orig_to_new, user_data); + break; + case GPU_BUFFER_TRIANGLES: + cdDM_buffer_copy_triangles(dm, varray, mat_orig_to_new, user_data); + break; + default: + break; + } +} + +/* add a new point to the list of points related to a particular + * vertex */ +#ifdef USE_GPU_POINT_LINK + +static void cdDM_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 cdDM_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 */ + +static int tri_indices[2][3] = {{0, 1, 2}, {2, 3, 0}}; + +/* update the vert_points and triangle_to_mface fields with a new + * triangle */ +static void cdDM_drawobject_add_triangle(GPUDrawObject *gdo, + int v1, int v2, int v3, bool quad, int loopindex) +{ + int i, v[3] = {v1, v2, v3}; + int *tri_i = quad ? tri_indices[1] : tri_indices[0]; + for (i = 0; i < 3; i++) + cdDM_drawobject_add_vert_point(gdo, v[i], loopindex + tri_i[i]); +} + +/* 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 cdDM_drawobject_init_vert_points(GPUDrawObject *gdo, MFace *f, int totface, int totmat) +{ + GPUBufferMaterial *mat; + int i, *mat_orig_to_new; + int tot_loops = 0; + + 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; + gdo->materials[i].counter = 0; + } + + /* -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]]; + + mat->polys[mat->counter++] = i; + + /* add triangle */ + cdDM_drawobject_add_triangle(gdo, f->v1, f->v2, f->v3, false, tot_loops); + mat->totelements += 3; + + /* add second triangle for quads */ + if (f->v4) { + cdDM_drawobject_add_triangle(gdo, f->v3, f->v4, f->v1, true, tot_loops); + mat->totelements += 3; + tot_loops += 4; + } + else { + tot_loops += 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); +} + +typedef struct { + int elements; + int loops; + int polys; +} GPUMaterialInfo; + +/* see GPUDrawObject's structure definition for a description of the + * data being initialized here */ +static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm) +{ + GPUDrawObject *gdo; + MFace *mface; + int totmat = dm->totmat; + GPUMaterialInfo *mat_info; + int i, curmat, totelements, totface, totloops; + + /* 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 */ + mat_info = MEM_callocN(sizeof(*mat_info) * totmat, "GPU_drawobject_new.mat_orig_to_new"); + for (i = 0; i < totface; i++) { + mat_info[mface[i].mat_nr].polys++; + if (mface[i].v4) { + mat_info[mface[i].mat_nr].elements += 6; + mat_info[mface[i].mat_nr].loops += 4; + } + else { + mat_info[mface[i].mat_nr].elements += 3; + mat_info[mface[i].mat_nr].loops += 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 (mat_info[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, totelements = 0, totloops = 0; i < totmat; i++) { + if (mat_info[i].elements > 0) { + gdo->materials[curmat].start = totelements; + /* can set it to points now but used in cdDM_drawobject_init_vert_points as counter */ + gdo->materials[curmat].totelements = 0; + gdo->materials[curmat].totloops = mat_info[i].loops; + gdo->materials[curmat].mat_nr = i; + gdo->materials[curmat].totpolys = mat_info[i].polys; + gdo->materials[curmat].polys = MEM_mallocN(sizeof(int) * mat_info[i].polys, "GPUBufferMaterial.polys"); + + totelements += mat_info[i].elements; + totloops += mat_info[i].loops; + curmat++; + } + } + + gdo->tot_loop_verts = totloops; + + /* store total number of points used for triangles */ + gdo->tot_triangle_point = totelements; + + cdDM_drawobject_init_vert_points(gdo, mface, totface, totmat); + MEM_freeN(mat_info); + + return gdo; +} + static void cdDM_foreachMappedVert( DerivedMesh *dm, void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]), @@ -1541,6 +2115,9 @@ static CDDerivedMesh *cdDM_create(const char *desc) dm->drawMappedFacesGLSL = cdDM_drawMappedFacesGLSL; dm->drawMappedFacesMat = cdDM_drawMappedFacesMat; + dm->copy_gpu_data = cdDM_copy_gpu_data; + dm->gpuObjectNew = cdDM_GPUobject_new; + dm->foreachMappedVert = cdDM_foreachMappedVert; dm->foreachMappedEdge = cdDM_foreachMappedEdge; dm->foreachMappedLoop = cdDM_foreachMappedLoop; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 361557633cb..e5e36b24a46 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -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; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index cc680224c31..733cb15ea86 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -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,86 +1799,469 @@ 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); - - 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; + 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]); + + 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); - - glNormal3fv(CCG_elem_no(&key, a)); - glVertex3fv(CCG_elem_co(&key, a)); - glNormal3fv(CCG_elem_no(&key, b)); - glVertex3fv(CCG_elem_co(&key, b)); + 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); + + 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); - - ccgDM_glNormalFast(a, b, c, d); - - glVertex3fv(d); - glVertex3fv(c); - glVertex3fv(b); - glVertex3fv(a); + 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_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); + + 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, DMSetDrawOptions setDrawOptions, @@ -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); + if (faceFlags) { + mat_nr = faceFlags[origIndex].mat_nr; + } + else { + mat_nr = 0; } - 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++; - } + 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 (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; - } - } + else if (index != ORIGINDEX_NONE) + draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL; + else + draw_option = DM_DRAW_OPTION_NORMAL; - a = CCG_grid_elem(&key, faceGridData, x, y + 0); - b = CCG_grid_elem(&key, faceGridData, x, y + 1); + /* flush buffer if current triangle isn't drawable or it's last triangle */ + flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 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 (!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 (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 (flush) { + if (draw_option != DM_DRAW_OPTION_SKIP) + tot_element += facequads * 6; - if (tf) tf++; - if (tf_stencil) tf_stencil++; - if (cp) cp += 16; + if (tot_element) { + if (mcol && draw_option != DM_DRAW_OPTION_NO_MCOL) + GPU_color_switch(1); + else + GPU_color_switch(0); - glEnd(); + GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, start_element, tot_element); } + + start_element = tot_element; } 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); - - 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; - } - } - glEnd(); + 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; diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 350ecf22e1b..07b9c60d101 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -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); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index bcbae9958d1..ac6329910c9 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -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); } |