diff options
author | Mike Erwin <significant.bit@gmail.com> | 2016-10-26 02:34:17 +0300 |
---|---|---|
committer | Mike Erwin <significant.bit@gmail.com> | 2016-10-26 02:34:17 +0300 |
commit | 456d145d070e456bd3836f3529453043ce53a0b0 (patch) | |
tree | 8f5fdb33136b8c71ea02820478085f41605f9d38 /source/blender/editors/space_view3d/drawobject.c | |
parent | 821fa248760bf97be88de7a9088f9038396278c3 (diff) |
OpenGL: new mesh draw routines for new viewport
Totally WIP.
Started with copies of legacy routines, modified to use the new shaders & batch cache. Not all features are implemented; this is why we keep legacy viewport around during development!
Diffstat (limited to 'source/blender/editors/space_view3d/drawobject.c')
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 468 |
1 files changed, 465 insertions, 3 deletions
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index ba3dfb71547..8df10074224 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -974,7 +974,7 @@ void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][ glDisableClientState(GL_VERTEX_ARRAY); } -void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos) +static void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos) { float verts[CIRCLE_RESOL][3]; @@ -4225,9 +4225,15 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #endif } +static void draw_em_fancy_new(Scene *scene, ARegion *ar, View3D *v3d, + Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt) +{ + /* for now... nothing! */ +} + /* Mesh drawing routines */ -void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) +void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) /* LEGACY */ { if ((v3d->transp == false) && /* not when we draw the transparent pass */ (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */ @@ -4251,6 +4257,51 @@ void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) } } +static void draw_mesh_object_outline_new(View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm) +{ + if ((v3d->transp == false) && /* not when we draw the transparent pass */ + (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */ + { + glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + glDepthMask(GL_FALSE); + + const float outline_color[4]; + UI_GetThemeColor4fv(TH_SELECT, outline_color); +#if 1 + Batch *fancy_edges = MBC_get_fancy_edges(dm); + + if (rv3d->persp == RV3D_ORTHO) { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO); + /* set eye vector, transformed to object coords */ + float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ + mul_m3_v3(gpuGetNormalMatrixInverse(NULL), eye); + Batch_Uniform3fv(fancy_edges, "eye", eye); + } + else { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP); + glEnable(GL_BLEND); /* hack until we support geometry shaders on Mac */ + } + + Batch_Uniform1b(fancy_edges, "drawFront", false); + Batch_Uniform1b(fancy_edges, "drawBack", false); + Batch_Uniform1b(fancy_edges, "drawSilhouette", true); + Batch_Uniform4fv(fancy_edges, "silhouetteColor", outline_color); + + Batch_draw(fancy_edges); + + if (rv3d->persp != RV3D_ORTHO) { + glDisable(GL_BLEND); /* hack */ + } +#else + Batch *batch = MBC_get_all_edges(dm); + Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform4fv(batch, "color", outline_color); + Batch_draw(batch); +#endif + glDepthMask(GL_TRUE); + } +} + static bool object_is_halo(Scene *scene, Object *ob) { const Material *ma = give_current_material(ob, 1); @@ -4629,6 +4680,412 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3 return retval; } +static void draw_mesh_fancy_new(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, + const char dt, const unsigned char ob_wire_col[4], const short dflag) +{ + if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) { + /* too complicated! use existing methods */ + /* TODO: move this into a separate depth pre-pass */ + draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + return; + } + +#ifdef WITH_GAMEENGINE + Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, scene) : base->object; +#else + Object *ob = base->object; +#endif + Mesh *me = ob->data; + eWireDrawMode draw_wire = OBDRAW_WIRE_OFF; /* could be bool draw_wire_overlay */ + bool no_edges, no_faces; + DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); + const bool is_obact = (ob == OBACT); + int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0; + + if (!dm) + return; + + const bool solid = dt >= OB_SOLID; + if (solid) { + DM_update_materials(dm, ob); + } + + /* Check to draw dynamic paint colors (or weights from WeightVG modifiers). + * Note: Last "preview-active" modifier in stack will win! */ + if (DM_get_loop_data_layer(dm, CD_PREVIEW_MLOOPCOL) && modifiers_isPreview(ob)) + draw_flags |= DRAW_MODIFIERS_PREVIEW; + + /* Unwanted combination */ + if (draw_flags & DRAW_FACE_SELECT) { + draw_wire = OBDRAW_WIRE_OFF; + } + else if (ob->dtx & OB_DRAWWIRE) { + draw_wire = OBDRAW_WIRE_ON; + } + + /* check polys instead of tessfaces because of dyntopo where tessfaces don't exist */ + if (dm->type == DM_TYPE_CCGDM) { + no_edges = !subsurf_has_edges(dm); + no_faces = !subsurf_has_faces(dm); + } + else { + no_edges = (dm->getNumEdges(dm) == 0); + no_faces = (dm->getNumPolys(dm) == 0); + } + + if (solid) { + /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */ + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); + } + + if (dt == OB_BOUNDBOX) { + if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0) + draw_bounding_volume(ob, ob->boundtype); + } + else if ((no_faces && no_edges) || + ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob))) + { + glPointSize(1.5); + // dm->drawVerts(dm); + // TODO: draw smooth round points as a batch + } + else if ((dt == OB_WIRE) || no_faces) { + draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */ + + /* TODO: enable depth for wireframes */ + + glLineWidth(1.0f); + + float color[4]; + rgba_uchar_to_float(color, ob_wire_col); + + /* TODO: + * const bool active = (ob == CTX_data_active_object(C)); + * const int theme = active ? TH_ACTIVE : (base->flag & SELECT) ? TH_SELECT : TH_WIRE; + * UI_GetThemeColor4fv(theme, color); + */ + +#if 0 + Batch *fancy_edges = MBC_get_fancy_edges(dm); + + if (rv3d->persp == RV3D_ORTHO) { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO); + /* set eye vector, transformed to object coords */ + float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ + mul_m3_v3(gpuGetNormalMatrixInverse(NULL), eye); + Batch_Uniform3fv(fancy_edges, "eye", eye); + } + else { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP); + } + + /* TODO: nice variations (lighter & darker shades) of base color */ + float backColor[4] = { 0.5f, 0.3f, 0.0f, 1.0f }; + float outlineColor[4] = { 1.0f, 0.7f, 0.3f, 1.0f }; + + Batch_Uniform4fv(fancy_edges, "frontColor", color); + Batch_Uniform4fv(fancy_edges, "backColor", backColor); + Batch_Uniform1b(fancy_edges, "drawFront", true); + Batch_Uniform1b(fancy_edges, "drawBack", true); + Batch_Uniform1b(fancy_edges, "drawSilhouette", true); + Batch_Uniform4fv(fancy_edges, "silhouetteColor", outlineColor); + + Batch_draw(fancy_edges); +#else + Batch *batch = MBC_get_all_edges(dm); + Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform4fv(batch, "color", color); + Batch_draw(batch); +#endif + } + else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) || + check_object_draw_texture(scene, v3d, dt)) + { + bool draw_loose = true; + + if ((v3d->flag & V3D_SELECT_OUTLINE) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (base->flag & SELECT) && + !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) && + (draw_wire == OBDRAW_WIRE_OFF)) + { + draw_mesh_object_outline_new(v3d, rv3d, ob, dm); + } + + if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) { + Paint *p; + + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); + + if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene))) { + GPUVertexAttribs gattribs; + float planes[4][4]; + float (*fpl)[4] = NULL; + const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING); + + if (ob->sculpt->partial_redraw) { + if (ar->do_draw & RGN_DRAW_PARTIAL) { + ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob); + fpl = planes; + ob->sculpt->partial_redraw = 0; + } + } + + GPU_object_material_bind(1, &gattribs); + dm->drawFacesSolid(dm, fpl, fast, NULL); + draw_loose = false; + } + else + dm->drawFacesGLSL(dm, GPU_object_material_bind); + + GPU_object_material_unbind(); + + glFrontFace(GL_CCW); + + if (draw_flags & DRAW_FACE_SELECT) + draw_mesh_face_select(rv3d, me, dm, false); + } + else { + draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags); + } + + if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) { + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + if ((dflag & DRAW_CONSTCOLOR) == 0) { + glColor3ubv(ob_wire_col); + } + glLineWidth(1.0f); + dm->drawLooseEdges(dm); + } + } + } + else if (dt == OB_SOLID) { + if (draw_flags & DRAW_MODIFIERS_PREVIEW) { + /* for object selection draws no shade */ + if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) { + /* TODO: draw basic faces with GPU_SHADER_3D_DEPTH_ONLY */ + } + else { + const float specular[3] = {0.47f, 0.47f, 0.47f}; + + /* draw outline */ + /* TODO: move this into a separate pass */ + if ((v3d->flag & V3D_SELECT_OUTLINE) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (base->flag & SELECT) && + (draw_wire == OBDRAW_WIRE_OFF) && + (ob->sculpt == NULL)) + { + draw_mesh_object_outline_new(v3d, rv3d, ob, dm); + } + + /* materials arent compatible with vertex colors */ + GPU_end_object_materials(); + + /* set default specular */ + GPU_basic_shader_colors(NULL, specular, 35, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); + + dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS | DM_DRAW_NEED_NORMALS); + + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + } + } + else { + Paint *p; + + if ((v3d->flag & V3D_SELECT_OUTLINE) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (base->flag & SELECT) && + (draw_wire == OBDRAW_WIRE_OFF) && + (ob->sculpt == NULL)) + { + /* TODO: move this into a separate pass */ + draw_mesh_object_outline_new(v3d, rv3d, ob, dm); + } + + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); + + if (ob->sculpt && (p = BKE_paint_get_active(scene))) { + float planes[4][4]; + float (*fpl)[4] = NULL; + const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING); + + if (ob->sculpt->partial_redraw) { + if (ar->do_draw & RGN_DRAW_PARTIAL) { + ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob); + fpl = planes; + ob->sculpt->partial_redraw = 0; + } + } + + dm->drawFacesSolid(dm, fpl, fast, GPU_object_material_bind); + } + else + dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); + + glFrontFace(GL_CCW); + + GPU_object_material_unbind(); + + if (!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + if ((dflag & DRAW_CONSTCOLOR) == 0) { + glColor3ubv(ob_wire_col); + } + glLineWidth(1.0f); + dm->drawLooseEdges(dm); + } + } + } + else if (dt == OB_PAINT) { + draw_mesh_paint(v3d, rv3d, ob, dm, draw_flags); + + /* since we already draw wire as wp guide, don't draw over the top */ + draw_wire = OBDRAW_WIRE_OFF; + } + + if ((draw_wire != OBDRAW_WIRE_OFF) && /* draw extra wire */ + /* when overriding with render only, don't bother */ + (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0)) // <-- is this "== 0" in the right spot??? + { + /* When using wireframe object draw in particle edit mode + * the mesh gets in the way of seeing the particles, fade the wire color + * with the background. */ + + if ((dflag & DRAW_CONSTCOLOR) == 0) { + /* TODO: + * Batch_UniformColor4ubv(ob_wire_col); + */ + } + + /* If drawing wire and drawtype is not OB_WIRE then we are + * overlaying the wires. + * + * No need for polygon offset because new technique is AWESOME. + */ +#if 0 + glLineWidth(1.0f); + dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0); +#else + /* something */ +#endif + } + +#if 0 // (merwin) what is this for? + if (is_obact && BKE_paint_select_vert_test(ob)) { + const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0; + glColor3f(0.0f, 0.0f, 0.0f); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + + if (!use_depth) glDisable(GL_DEPTH_TEST); + else ED_view3d_polygon_offset(rv3d, 1.0); + drawSelectedVertices(dm, ob->data); + if (!use_depth) glEnable(GL_DEPTH_TEST); + else ED_view3d_polygon_offset(rv3d, 0.0); + } +#endif + + dm->release(dm); +} + +static bool draw_mesh_object_new(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, + const char dt, const unsigned char ob_wire_col[4], const short dflag) +{ + Object *ob = base->object; + Object *obedit = scene->obedit; + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + bool do_alpha_after = false, drawlinked = false, retval = false; + + if (v3d->flag2 & V3D_RENDER_SHADOW) { + /* TODO: handle shadow pass separately */ + return true; + } + + if (obedit && ob != obedit && ob->data == obedit->data) { + if (BKE_key_from_object(ob) || BKE_key_from_object(obedit)) {} + else if (ob->modifiers.first || obedit->modifiers.first) {} + else drawlinked = true; + } + + /* backface culling */ + const bool solid = dt > OB_WIRE; + const bool cullBackface = solid && (v3d->flag2 & V3D_BACKFACE_CULLING); + if (cullBackface) { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + } + + if (ob == obedit || drawlinked) { + DerivedMesh *finalDM, *cageDM; + + if (obedit != ob) { + /* linked to the edit object */ + finalDM = cageDM = editbmesh_get_derived_base( + ob, em, scene->customdata_mask); + } + else { + cageDM = editbmesh_get_derived_cage_and_final( + scene, ob, em, scene->customdata_mask, + &finalDM); + } + + const bool use_material = solid && ((me->drawflag & ME_DRAWEIGHT) == 0); + +#if 0 // why update if not being used? + DM_update_materials(finalDM, ob); + if (cageDM != finalDM) { + DM_update_materials(cageDM, ob); + } +#endif // moved to below + + if (use_material) { + DM_update_materials(finalDM, ob); + if (cageDM != finalDM) { + DM_update_materials(cageDM, ob); + } + + const bool glsl = draw_glsl_material(scene, ob, v3d, dt); + + GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); + } + + draw_em_fancy_new(scene, ar, v3d, ob, em, cageDM, finalDM, dt); + + if (use_material) { + GPU_end_object_materials(); + } + + if (obedit != ob) + finalDM->release(finalDM); + } + else { + /* ob->bb was set by derived mesh system, do NULL check just to be sure */ + if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) { + if (solid) { + const bool glsl = draw_glsl_material(scene, ob, v3d, dt); + + if (dt == OB_SOLID || glsl) { + const bool check_alpha = check_alpha_pass(base); + GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, + (check_alpha) ? &do_alpha_after : NULL); + } + } + + draw_mesh_fancy_new(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + + GPU_end_object_materials(); + + if (me->totvert == 0) retval = true; + } + } + + if (cullBackface) + glDisable(GL_CULL_FACE); + + return retval; +} + /* ************** DRAW DISPLIST ****************** */ @@ -6918,7 +7375,12 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short switch (ob->type) { case OB_MESH: - empty_object = draw_mesh_object(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + if (IS_VIEWPORT_LEGACY(v3d)) { + empty_object = draw_mesh_object(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + } + else { + empty_object = draw_mesh_object_new(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + } if ((dflag & DRAW_CONSTCOLOR) == 0) { /* mesh draws wire itself */ dtx &= ~OB_DRAWWIRE; |