/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * Contributor(s): Blender Foundation, full recode and added functions * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/editors/space_view3d/drawobject.c * \ingroup spview3d */ #include "MEM_guardedalloc.h" #include "DNA_camera_types.h" #include "DNA_curve_types.h" #include "DNA_constraint_types.h" /* for drawing constraint */ #include "DNA_lamp_types.h" #include "DNA_lattice_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_smoke_types.h" #include "DNA_world_types.h" #include "DNA_object_types.h" #include "BLI_listbase.h" #include "BLI_link_utils.h" #include "BLI_string.h" #include "BLI_math.h" #include "BLI_memarena.h" #include "BKE_anim.h" /* for the where_on_path function */ #include "BKE_armature.h" #include "BKE_camera.h" #include "BKE_colortools.h" #include "BKE_constraint.h" /* for the get_constraint_target function */ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_DerivedMesh.h" #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_key.h" #include "BKE_layer.h" #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_modifier.h" #include "BKE_movieclip.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_scene.h" #include "BKE_subsurf.h" #include "BKE_unit.h" #include "BKE_tracking.h" #include "BKE_editmesh.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "BIF_gl.h" #include "BIF_glutil.h" #include "GPU_draw.h" #include "GPU_select.h" #include "GPU_basic_shader.h" #include "GPU_shader.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" #include "GPU_batch.h" #include "GPU_matrix.h" #include "GPU_state.h" #include "GPU_framebuffer.h" #include "ED_mesh.h" #include "ED_particle.h" #include "ED_screen.h" #include "ED_sculpt.h" #include "ED_types.h" #include "UI_resources.h" #include "UI_interface_icons.h" #include "WM_api.h" #include "BLF_api.h" #include "view3d_intern.h" /* bad level include */ #include "../../draw/intern/draw_cache_impl.h" /* bad level include (temporary) */ int view3d_effective_drawtype(const struct View3D *v3d) { if (v3d->drawtype == OB_RENDER) { return v3d->prev_drawtype; } return v3d->drawtype; } static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt) { if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0) return false; if (G.f & G_BACKBUFSEL) return false; if ((vd->flag & V3D_ZBUF_SELECT) == 0) return true; /* if its drawing textures with zbuf sel, then don't draw dots */ if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE) return false; if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX)) return false; return true; } /* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */ /* 32 values of sin function (still same result!) */ #define CIRCLE_RESOL 32 static const float sinval[CIRCLE_RESOL] = { 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213, 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196, 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573, -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278, -0.57126821, -0.39435585, -0.20129852, 0.00000000 }; /* 32 values of cos function (still same result!) */ static const float cosval[CIRCLE_RESOL] = { 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525, 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661, -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598, -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691, 0.82076344, 0.91895781, 0.97952994, 1.00000000 }; static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4]) { float vx[3], vy[3]; float *viter = (float *)verts; mul_v3_v3fl(vx, tmat[0], rad); mul_v3_v3fl(vy, tmat[1], rad); for (unsigned int a = 0; a < CIRCLE_RESOL; a++, viter += 3) { viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0]; viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1]; viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2]; } } void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos) { float verts[CIRCLE_RESOL][3]; circball_array_fill(verts, cent, rad, tmat); immBegin(GWN_PRIM_LINE_LOOP, CIRCLE_RESOL); for (int i = 0; i < CIRCLE_RESOL; ++i) { immVertex3fv(pos, verts[i]); } immEnd(); } #ifdef VIEW3D_CAMERA_BORDER_HACK unsigned char view3d_camera_border_hack_col[3]; bool view3d_camera_border_hack_test = false; #endif /* ***************** BACKBUF SEL (BBS) ********* */ #ifdef USE_MESH_DM_SELECT static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const float co[3], const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) { drawMVertOffset_userData *data = userData; MVert *mv = &data->mvert[index]; if (!(mv->flag & ME_HIDE)) { int selcol; GPU_select_index_get(data->offset + index, &selcol); immAttrib1u(data->col, selcol); immVertex3fv(data->pos, co); } } static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *dm, int offset) { drawMVertOffset_userData data; Mesh *me = ob->data; MVert *mvert = me->mvert; data.mvert = mvert; data.offset = offset; const int imm_len = dm->getNumVerts(dm); if (imm_len == 0) return; Gwn_VertFormat *format = immVertexFormat(); data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U32, 1, GWN_FETCH_INT); immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32); GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE)); immBeginAtMost(GWN_PRIM_POINTS, imm_len); dm->foreachMappedVert(dm, bbs_obmode_mesh_verts__mapFunc, &data, DM_FOREACH_NOP); immEnd(); immUnbindProgram(); } #else static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *UNUSED(dm), int offset) { Mesh *me = ob->data; Gwn_Batch *batch = DRW_mesh_batch_cache_get_verts_with_select_id(me, offset); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); GWN_batch_draw(batch); } #endif #ifdef USE_MESH_DM_SELECT static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3], const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) { drawBMOffset_userData *data = userData; BMVert *eve = BM_vert_at_index(data->bm, index); if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { int selcol; GPU_select_index_get(data->offset + index, &selcol); immAttrib1u(data->col, selcol); immVertex3fv(data->pos, co); } } static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset) { drawBMOffset_userData data; data.bm = em->bm; data.offset = offset; Gwn_VertFormat *format = immVertexFormat(); data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U32, 1, GWN_FETCH_INT); immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32); GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE)); immBeginAtMost(GWN_PRIM_POINTS, em->bm->totvert); dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, &data, DM_FOREACH_NOP); immEnd(); immUnbindProgram(); } #else static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *UNUSED(dm), int offset) { GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE)); Mesh *me = em->ob->data; Gwn_Batch *batch = DRW_mesh_batch_cache_get_verts_with_select_id(me, offset); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); GWN_batch_draw(batch); } #endif #ifdef USE_MESH_DM_SELECT static void bbs_mesh_wire__mapFunc(void *userData, int index, const float v0co[3], const float v1co[3]) { drawBMOffset_userData *data = userData; BMEdge *eed = BM_edge_at_index(data->bm, index); if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { int selcol; GPU_select_index_get(data->offset + index, &selcol); immAttrib1u(data->col, selcol); immVertex3fv(data->pos, v0co); immVertex3fv(data->pos, v1co); } } static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) { drawBMOffset_userData data; data.bm = em->bm; data.offset = offset; Gwn_VertFormat *format = immVertexFormat(); const int imm_len = dm->getNumEdges(dm) * 2; if (imm_len == 0) return; data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U32, 1, GWN_FETCH_INT); immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32); GPU_line_width(1.0f); immBeginAtMost(GWN_PRIM_LINES, imm_len); dm->foreachMappedEdge(dm, bbs_mesh_wire__mapFunc, &data); immEnd(); immUnbindProgram(); } #else static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *UNUSED(dm), int offset) { GPU_line_width(1.0f); Mesh *me = em->ob->data; Gwn_Batch *batch = DRW_mesh_batch_cache_get_edges_with_select_id(me, offset); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); GWN_batch_draw(batch); } #endif #ifdef USE_MESH_DM_SELECT static void bbs_mesh_face(BMEditMesh *em, DerivedMesh *dm, const bool use_select) { UNUSED_VARS(dm); drawBMOffset_userData data; data.bm = em->bm; const int tri_len = em->tottri; const int imm_len = tri_len * 3; const char hflag_skip = use_select ? BM_ELEM_HIDDEN : (BM_ELEM_HIDDEN | BM_ELEM_SELECT); if (imm_len == 0) return; Gwn_VertFormat *format = immVertexFormat(); data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U32, 1, GWN_FETCH_INT); immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32); immBeginAtMost(GWN_PRIM_TRIS, imm_len); if (use_select == false) { int selcol; GPU_select_index_get(0, &selcol); immAttrib1u(data.col, selcol); } int index = 0; while (index < tri_len) { const BMFace *f = em->looptris[index][0]->f; const int ntris = f->len - 2; if (!BM_elem_flag_test(f, hflag_skip)) { if (use_select) { int selcol; GPU_select_index_get(BM_elem_index_get(f) + 1, &selcol); immAttrib1u(data.col, selcol); } for (int t = 0; t < ntris; t++) { immVertex3fv(data.pos, em->looptris[index][0]->v->co); immVertex3fv(data.pos, em->looptris[index][1]->v->co); immVertex3fv(data.pos, em->looptris[index][2]->v->co); index++; } } else { index += ntris; } } immEnd(); immUnbindProgram(); } #else static void bbs_mesh_face(BMEditMesh *em, DerivedMesh *UNUSED(dm), const bool use_select) { Mesh *me = em->ob->data; Gwn_Batch *batch; if (use_select) { batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, true, 1); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); GWN_batch_draw(batch); } else { int selcol; GPU_select_index_get(0, &selcol); batch = DRW_mesh_batch_cache_get_triangles_with_select_mask(me, true); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR_U32); GWN_batch_uniform_1ui(batch, "color", selcol); GWN_batch_draw(batch); } } #endif #ifdef USE_MESH_DM_SELECT static void bbs_mesh_solid__drawCenter(void *userData, int index, const float cent[3], const float UNUSED(no[3])) { drawBMOffset_userData *data = (drawBMOffset_userData *)userData; BMFace *efa = BM_face_at_index(userData, index); if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { int selcol; GPU_select_index_get(index + 1, &selcol); immAttrib1u(data->col, selcol); immVertex3fv(data->pos, cent); } } static void bbs_mesh_face_dot(BMEditMesh *em, DerivedMesh *dm) { drawBMOffset_userData data; /* don't use offset */ data.bm = em->bm; Gwn_VertFormat *format = immVertexFormat(); data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U32, 1, GWN_FETCH_INT); immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32); GPU_point_size(UI_GetThemeValuef(TH_FACEDOT_SIZE)); immBeginAtMost(GWN_PRIM_POINTS, em->bm->totface); dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, &data, DM_FOREACH_NOP); immEnd(); immUnbindProgram(); } #else static void bbs_mesh_face_dot(BMEditMesh *em, DerivedMesh *UNUSED(dm)) { Mesh *me = em->ob->data; Gwn_Batch *batch = DRW_mesh_batch_cache_get_facedots_with_select_id(me, 1); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); GWN_batch_draw(batch); } #endif /* two options, facecolors or black */ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, DerivedMesh *dm, bool use_faceselect) { if (use_faceselect) { bbs_mesh_face(em, dm, true); if (check_ob_drawface_dot(scene, v3d, ob->dt)) { bbs_mesh_face_dot(em, dm); } } else { bbs_mesh_face(em, dm, false); } } #ifdef USE_MESH_DM_SELECT /* must have called GPU_framebuffer_index_set beforehand */ static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index) { Mesh *me = userData; if (!(me->mpoly[index].flag & ME_HIDE)) { return DM_DRAW_OPTION_NORMAL; } else { return DM_DRAW_OPTION_SKIP; } } static void bbs_mesh_solid_verts(Depsgraph *depsgraph, Scene *scene, Object *ob) { Mesh *me = ob->data; DerivedMesh *dm = mesh_get_derived_final(depsgraph, scene, ob, scene->customdata_mask); DM_update_materials(dm, ob); /* Only draw faces to mask out verts, we don't want their selection ID's. */ const int G_f_orig = G.f; G.f &= ~G_BACKBUFSEL; dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, NULL, NULL, me, DM_DRAW_SKIP_HIDDEN); G.f |= (G_f_orig & G_BACKBUFSEL); bbs_obmode_mesh_verts(ob, dm, 1); bm_vertoffs = me->totvert + 1; dm->release(dm); } #else static void bbs_mesh_solid_verts(Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene), Object *ob) { Mesh *me = ob->data; /* Only draw faces to mask out verts, we don't want their selection ID's. */ const int G_f_orig = G.f; G.f &= ~G_BACKBUFSEL; { int selcol; Gwn_Batch *batch; GPU_select_index_get(0, &selcol); batch = DRW_mesh_batch_cache_get_triangles_with_select_mask(me, true); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR_U32); GWN_batch_uniform_1ui(batch, "color", selcol); GWN_batch_draw(batch); } G.f |= (G_f_orig & G_BACKBUFSEL); bbs_obmode_mesh_verts(ob, NULL, 1); bm_vertoffs = me->totvert + 1; } #endif static void bbs_mesh_solid_faces(Scene *UNUSED(scene), Object *ob) { Mesh *me = ob->data; Gwn_Batch *batch; if ((me->editflag & ME_EDIT_PAINT_FACE_SEL)) { batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, true, 1); } else { batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, false, 1); } GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); GWN_batch_draw(batch); } void draw_object_backbufsel( Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, short select_mode) { ToolSettings *ts = scene->toolsettings; if (select_mode == -1) { select_mode = ts->selectmode; } gpuMultMatrix(ob->obmat); glClearDepth(1.0); GPU_clear(GPU_DEPTH_BIT); GPU_depth_test(true); switch (ob->type) { case OB_MESH: if (ob->mode & OB_MODE_EDIT) { Mesh *me = ob->data; BMEditMesh *em = me->edit_btmesh; DerivedMesh *dm = editbmesh_get_derived_cage(depsgraph, scene, ob, em, CD_MASK_BAREMESH); BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE); DM_update_materials(dm, ob); bbs_mesh_solid_EM(em, scene, v3d, ob, dm, (select_mode & SCE_SELECT_FACE) != 0); if (select_mode & SCE_SELECT_FACE) bm_solidoffs = 1 + em->bm->totface; else { bm_solidoffs = 1; } ED_view3d_polygon_offset(rv3d, 1.0); /* we draw edges if edge select mode */ if (select_mode & SCE_SELECT_EDGE) { bbs_mesh_wire(em, dm, bm_solidoffs); bm_wireoffs = bm_solidoffs + em->bm->totedge; } else { /* `bm_vertoffs` is calculated from `bm_wireoffs`. (otherwise see T53512) */ bm_wireoffs = bm_solidoffs; } /* we draw verts if vert select mode. */ if (select_mode & SCE_SELECT_VERTEX) { bbs_mesh_verts(em, dm, bm_wireoffs); bm_vertoffs = bm_wireoffs + em->bm->totvert; } else { bm_vertoffs = bm_wireoffs; } ED_view3d_polygon_offset(rv3d, 0.0); dm->release(dm); } else { Mesh *me = ob->data; if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && /* currently vertex select supports weight paint and vertex paint*/ ((ob->mode & OB_MODE_WEIGHT_PAINT) || (ob->mode & OB_MODE_VERTEX_PAINT))) { bbs_mesh_solid_verts(depsgraph, scene, ob); } else { bbs_mesh_solid_faces(scene, ob); } } break; case OB_CURVE: case OB_SURF: break; } gpuLoadMatrix(rv3d->viewmat); } void ED_draw_object_facemap( Depsgraph *depsgraph, Scene *scene, Object *ob, const float col[4], const int facemap) { DerivedMesh *dm = NULL; /* happens on undo */ if (ob->type != OB_MESH || !ob->data) return; /* Temporary, happens on undo, would resolve but will eventually move away from DM. */ if (ob->derivedFinal == NULL) { return; } dm = mesh_get_derived_final(depsgraph, scene, ob, CD_MASK_BAREMESH); if (!dm || !CustomData_has_layer(&dm->polyData, CD_FACEMAP)) return; glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); #if 0 DM_update_materials(dm, ob); /* add polygon offset so we draw above the original surface */ glPolygonOffset(1.0, 1.0); GPU_facemap_setup(dm); glColor4fv(col); gpuPushAttrib(GL_ENABLE_BIT); GPU_blend(true); glDisable(GL_LIGHTING); /* always draw using backface culling */ glEnable(GL_CULL_FACE); glCullFace(GL_BACK); if (dm->drawObject->facemapindices) { glDrawElements(GL_TRIANGLES, dm->drawObject->facemap_count[facemap] * 3, GL_UNSIGNED_INT, (int *)NULL + dm->drawObject->facemap_start[facemap] * 3); } gpuPopAttrib(); GPU_buffers_unbind(); glPolygonOffset(0.0, 0.0); #else /* Just to create the data to pass to immediate mode, grr! */ Mesh *me = ob->data; const int *facemap_data = CustomData_get_layer(&me->pdata, CD_FACEMAP); if (facemap_data) { Gwn_VertFormat *format = immVertexFormat(); uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor4fv(col); /* XXX, alpha isn't working yet, not sure why. */ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); GPU_blend(true); MVert *mvert; MPoly *mpoly; int mpoly_len; MLoop *mloop; int mloop_len; if (dm && CustomData_has_layer(&dm->polyData, CD_FACEMAP)) { mvert = dm->getVertArray(dm); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); mpoly_len = dm->getNumPolys(dm); mloop_len = dm->getNumLoops(dm); facemap_data = CustomData_get_layer(&dm->polyData, CD_FACEMAP); } else { mvert = me->mvert; mpoly = me->mpoly; mloop = me->mloop; mpoly_len = me->totpoly; mloop_len = me->totloop; facemap_data = CustomData_get_layer(&me->pdata, CD_FACEMAP); } /* use gawain immediate mode fore now */ const int looptris_len = poly_to_tri_count(mpoly_len, mloop_len); immBeginAtMost(GWN_PRIM_TRIS, looptris_len * 3); MPoly *mp; int i; for (mp = mpoly, i = 0; i < mpoly_len; i++, mp++) { if (facemap_data[i] == facemap) { /* Weak, fan-fill, use until we have derived-mesh replaced. */ const MLoop *ml_start = &mloop[mp->loopstart]; const MLoop *ml_a = ml_start + 1; const MLoop *ml_b = ml_start + 2; for (int j = 2; j < mp->totloop; j++) { immVertex3fv(pos, mvert[ml_start->v].co); immVertex3fv(pos, mvert[ml_a->v].co); immVertex3fv(pos, mvert[ml_b->v].co); ml_a++; ml_b++; } } } immEnd(); immUnbindProgram(); GPU_blend(false); } #endif dm->release(dm); }