/* * ***** 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) 2008, Blender Foundation * This is a new part of Blender * * Contributor(s): Antonio Vazquez * * ***** END GPL LICENSE BLOCK ***** */ /** \file draw/engines/gpencil/gpencil_draw_cache_impl.c * \ingroup draw */ #include "BLI_polyfill_2d.h" #include "BLI_math_color.h" #include "DNA_meshdata_types.h" #include "DNA_gpencil_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" #include "BKE_action.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "DRW_render.h" #include "GPU_immediate.h" #include "GPU_draw.h" #include "ED_gpencil.h" #include "ED_view3d.h" #include "UI_resources.h" #include "gpencil_engine.h" /* Helper to add stroke point to vbo */ static void gpencil_set_stroke_point( GPUVertBuf *vbo, const bGPDspoint *pt, int idx, uint pos_id, uint color_id, uint thickness_id, uint uvdata_id, short thickness, const float ink[4]) { float alpha = ink[3] * pt->strength; CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); float col[4]; ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha); GPU_vertbuf_attr_set(vbo, color_id, idx, col); /* transfer both values using the same shader variable */ float uvdata[2] = { pt->uv_fac, pt->uv_rot }; GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata); /* the thickness of the stroke must be affected by zoom, so a pixel scale is calculated */ float thick = max_ff(pt->pressure * thickness, 1.0f); GPU_vertbuf_attr_set(vbo, thickness_id, idx, &thick); GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); } /* Helper to add a new fill point and texture coordinates to vertex buffer */ static void gpencil_set_fill_point( GPUVertBuf *vbo, int idx, bGPDspoint *pt, const float fcolor[4], float uv[2], uint pos_id, uint color_id, uint text_id) { GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor); GPU_vertbuf_attr_set(vbo, text_id, idx, uv); } /* create batch geometry data for points stroke shader */ GPUBatch *DRW_gpencil_get_point_geom(bGPDstroke *gps, short thickness, const float ink[4]) { static GPUVertFormat format = { 0 }; static uint pos_id, color_id, size_id, uvdata_id; if (format.attr_len == 0) { pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); size_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); GPU_vertbuf_data_alloc(vbo, gps->totpoints); /* draw stroke curve */ const bGPDspoint *pt = gps->points; int idx = 0; float alpha; float col[4]; for (int i = 0; i < gps->totpoints; i++, pt++) { /* set point */ alpha = ink[3] * pt->strength; CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha); float thick = max_ff(pt->pressure * thickness, 1.0f); GPU_vertbuf_attr_set(vbo, color_id, idx, col); GPU_vertbuf_attr_set(vbo, size_id, idx, &thick); /* transfer both values using the same shader variable */ float uvdata[2] = { pt->uv_fac, pt->uv_rot }; GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata); GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); idx++; } return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); } /* create batch geometry data for stroke shader */ GPUBatch *DRW_gpencil_get_stroke_geom(bGPDstroke *gps, short thickness, const float ink[4]) { bGPDspoint *points = gps->points; int totpoints = gps->totpoints; /* if cyclic needs more vertex */ int cyclic_add = (gps->flag & GP_STROKE_CYCLIC) ? 1 : 0; static GPUVertFormat format = { 0 }; static uint pos_id, color_id, thickness_id, uvdata_id; if (format.attr_len == 0) { pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); GPU_vertbuf_data_alloc(vbo, totpoints + cyclic_add + 2); /* draw stroke curve */ const bGPDspoint *pt = points; int idx = 0; for (int i = 0; i < totpoints; i++, pt++) { /* first point for adjacency (not drawn) */ if (i == 0) { if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) { gpencil_set_stroke_point( vbo, &points[totpoints - 1], idx, pos_id, color_id, thickness_id, uvdata_id, thickness, ink); idx++; } else { gpencil_set_stroke_point( vbo, &points[1], idx, pos_id, color_id, thickness_id, uvdata_id, thickness, ink); idx++; } } /* set point */ gpencil_set_stroke_point( vbo, pt, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, ink); idx++; } if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) { /* draw line to first point to complete the cycle */ gpencil_set_stroke_point( vbo, &points[0], idx, pos_id, color_id, thickness_id, uvdata_id, thickness, ink); idx++; /* now add adjacency point (not drawn) */ gpencil_set_stroke_point( vbo, &points[1], idx, pos_id, color_id, thickness_id, uvdata_id, thickness, ink); idx++; } /* last adjacency point (not drawn) */ else { gpencil_set_stroke_point( vbo, &points[totpoints - 2], idx, pos_id, color_id, thickness_id, uvdata_id, thickness, ink); } return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO); } /* create batch geometry data for current buffer stroke shader */ GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; View3D *v3d = draw_ctx->v3d; ARegion *ar = draw_ctx->ar; RegionView3D *rv3d = draw_ctx->rv3d; ToolSettings *ts = scene->toolsettings; Object *ob = draw_ctx->obact; tGPspoint *points = gpd->runtime.sbuffer; int totpoints = gpd->runtime.sbuffer_size; static GPUVertFormat format = { 0 }; static uint pos_id, color_id, thickness_id, uvdata_id; if (format.attr_len == 0) { pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); GPU_vertbuf_data_alloc(vbo, totpoints + 2); /* draw stroke curve */ const tGPspoint *tpt = points; bGPDspoint pt, pt2; int idx = 0; /* get origin to reproject point */ float origin[3]; bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin); for (int i = 0; i < totpoints; i++, tpt++) { ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt); ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); /* first point for adjacency (not drawn) */ if (i == 0) { if (totpoints > 1) { ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt2); gpencil_set_stroke_point( vbo, &pt2, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); } else { gpencil_set_stroke_point( vbo, &pt, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); } idx++; } /* set point */ gpencil_set_stroke_point( vbo, &pt, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); idx++; } /* last adjacency point (not drawn) */ if (totpoints > 2) { ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2); gpencil_set_stroke_point( vbo, &pt2, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); } else { gpencil_set_stroke_point( vbo, &pt, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); } return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO); } /* create batch geometry data for current buffer point shader */ GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; View3D *v3d = draw_ctx->v3d; ARegion *ar = draw_ctx->ar; RegionView3D *rv3d = draw_ctx->rv3d; ToolSettings *ts = scene->toolsettings; Object *ob = draw_ctx->obact; tGPspoint *points = gpd->runtime.sbuffer; int totpoints = gpd->runtime.sbuffer_size; static GPUVertFormat format = { 0 }; static uint pos_id, color_id, thickness_id, uvdata_id; if (format.attr_len == 0) { pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); GPU_vertbuf_data_alloc(vbo, totpoints); /* draw stroke curve */ const tGPspoint *tpt = points; bGPDspoint pt; int idx = 0; /* get origin to reproject point */ float origin[3]; bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin); for (int i = 0; i < totpoints; i++, tpt++) { ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt); ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); /* set point */ gpencil_set_stroke_point( vbo, &pt, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); idx++; } return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); } /* create batch geometry data for current buffer fill shader */ GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd) { if (gpd == NULL) { return NULL; } const tGPspoint *points = gpd->runtime.sbuffer; int totpoints = gpd->runtime.sbuffer_size; if (totpoints < 3) { return NULL; } const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; View3D *v3d = draw_ctx->v3d; ARegion *ar = draw_ctx->ar; ToolSettings *ts = scene->toolsettings; Object *ob = draw_ctx->obact; /* get origin to reproject point */ float origin[3]; bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin); int tot_triangles = totpoints - 2; /* allocate memory for temporary areas */ uint (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, __func__); float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, __func__); /* Convert points to array and triangulate * Here a cache is not used because while drawing the information changes all the time, so the cache * would be recalculated constantly, so it is better to do direct calculation for each function call */ for (int i = 0; i < totpoints; i++) { const tGPspoint *pt = &points[i]; points2d[i][0] = pt->x; points2d[i][1] = pt->y; } BLI_polyfill_calc(points2d, (uint)totpoints, 0, tmp_triangles); static GPUVertFormat format = { 0 }; static uint pos_id, color_id; if (format.attr_len == 0) { pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); /* draw triangulation data */ if (tot_triangles > 0) { GPU_vertbuf_data_alloc(vbo, tot_triangles * 3); const tGPspoint *tpt; bGPDspoint pt; int idx = 0; for (int i = 0; i < tot_triangles; i++) { for (int j = 0; j < 3; j++) { tpt = &points[tmp_triangles[i][j]]; ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt); GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt.x); GPU_vertbuf_attr_set(vbo, color_id, idx, gpd->runtime.sfill); idx++; } } } /* clear memory */ if (tmp_triangles) { MEM_freeN(tmp_triangles); } if (points2d) { MEM_freeN(points2d); } return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); } /* create batch geometry data for stroke shader */ GPUBatch *DRW_gpencil_get_fill_geom(Object *ob, bGPDstroke *gps, const float color[4]) { BLI_assert(gps->totpoints >= 3); /* Calculate triangles cache for filling area (must be done only after changes) */ if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) { DRW_gpencil_triangulate_stroke_fill(gps); ED_gpencil_calc_stroke_uv(ob, gps); } BLI_assert(gps->tot_triangles >= 1); static GPUVertFormat format = { 0 }; static uint pos_id, color_id, text_id; if (format.attr_len == 0) { pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); text_id = GPU_vertformat_attr_add(&format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); GPU_vertbuf_data_alloc(vbo, gps->tot_triangles * 3); /* Draw all triangles for filling the polygon (cache must be calculated before) */ bGPDtriangle *stroke_triangle = gps->triangles; int idx = 0; for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) { for (int j = 0; j < 3; j++) { gpencil_set_fill_point( vbo, idx, &gps->points[stroke_triangle->verts[j]], color, stroke_triangle->uv[j], pos_id, color_id, text_id); idx++; } } return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); } /* Draw selected verts for strokes being edited */ GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag) { const DRWContextState *draw_ctx = DRW_context_state_get(); Object *ob = draw_ctx->obact; bGPdata *gpd = ob->data; bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); int vgindex = ob->actdef - 1; if (!BLI_findlink(&ob->defbase, vgindex)) { vgindex = -1; } /* Get size of verts: * - The selected state needs to be larger than the unselected state so that * they stand out more. * - We use the theme setting for size of the unselected verts */ float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE); float vsize; if ((int)bsize > 8) { vsize = 10.0f; bsize = 8.0f; } else { vsize = bsize + 2; } /* for now, we assume that the base color of the points is not too close to the real color */ float selectColor[4]; UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); selectColor[3] = alpha; static GPUVertFormat format = { 0 }; static uint pos_id, color_id, size_id; if (format.attr_len == 0) { pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); GPU_vertbuf_data_alloc(vbo, gps->totpoints); /* Draw start and end point differently if enabled stroke direction hint */ bool show_direction_hint = (dflag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1); /* Draw all the stroke points (selected or not) */ bGPDspoint *pt = gps->points; MDeformVert *dvert = gps->dvert; int idx = 0; float fcolor[4]; float fsize = 0; for (int i = 0; i < gps->totpoints; i++, pt++) { /* weight paint */ if (is_weight_paint) { float weight = gps->dvert ? defvert_find_weight(dvert, vgindex) : 0.0f; float hue = 2.0f * (1.0f - weight) / 3.0f; hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]); selectColor[3] = 1.0f; copy_v4_v4(fcolor, selectColor); fsize = vsize; } else { if (show_direction_hint && i == 0) { /* start point in green bigger */ ARRAY_SET_ITEMS(fcolor, 0.0f, 1.0f, 0.0f, 1.0f); fsize = vsize + 4; } else if (show_direction_hint && (i == gps->totpoints - 1)) { /* end point in red smaller */ ARRAY_SET_ITEMS(fcolor, 1.0f, 0.0f, 0.0f, 1.0f); fsize = vsize + 1; } else if (pt->flag & GP_SPOINT_SELECT) { copy_v4_v4(fcolor, selectColor); fsize = vsize; } else { copy_v4_v4(fcolor, gps->runtime.tmp_stroke_rgba); fsize = bsize; } } GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor); GPU_vertbuf_attr_set(vbo, size_id, idx, &fsize); GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); idx++; if (gps->dvert != NULL) { dvert++; } } return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); } /* Draw lines for strokes being edited */ GPUBatch *DRW_gpencil_get_edlin_geom(bGPDstroke *gps, float alpha, short UNUSED(dflag)) { const DRWContextState *draw_ctx = DRW_context_state_get(); Object *ob = draw_ctx->obact; bGPdata *gpd = ob->data; bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); int vgindex = ob->actdef - 1; if (!BLI_findlink(&ob->defbase, vgindex)) { vgindex = -1; } float selectColor[4]; UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); selectColor[3] = alpha; float linecolor[4]; copy_v4_v4(linecolor, gpd->line_color); static GPUVertFormat format = { 0 }; static uint pos_id, color_id; if (format.attr_len == 0) { pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); GPU_vertbuf_data_alloc(vbo, gps->totpoints); /* Draw all the stroke lines (selected or not) */ bGPDspoint *pt = gps->points; MDeformVert *dvert = gps->dvert; int idx = 0; float fcolor[4]; for (int i = 0; i < gps->totpoints; i++, pt++) { /* weight paint */ if (is_weight_paint) { float weight = gps->dvert ? defvert_find_weight(dvert, vgindex) : 0.0f; float hue = 2.0f * (1.0f - weight) / 3.0f; hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]); selectColor[3] = 1.0f; copy_v4_v4(fcolor, selectColor); } else { if (pt->flag & GP_SPOINT_SELECT) { copy_v4_v4(fcolor, selectColor); } else { copy_v4_v4(fcolor, linecolor); } } GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor); GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); idx++; if (gps->dvert != NULL) { dvert++; } } return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO); } static void set_grid_point( GPUVertBuf *vbo, int idx, float col_grid[4], uint pos_id, uint color_id, float v1, float v2, int axis) { GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid); float pos[3]; /* Set the grid in the selected axis (default is always Y axis) */ if (axis & V3D_GP_GRID_AXIS_X) { pos[0] = 0.0f; pos[1] = v1; pos[2] = v2; } else if (axis & V3D_GP_GRID_AXIS_Z) { pos[0] = v1; pos[1] = v2; pos[2] = 0.0f; } else { pos[0] = v1; pos[1] = 0.0f; pos[2] = v2; } GPU_vertbuf_attr_set(vbo, pos_id, idx, pos); } /* Draw grid lines */ GPUBatch *DRW_gpencil_get_grid(void) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; ToolSettings *ts = scene->toolsettings; View3D *v3d = draw_ctx->v3d; float col_grid[4]; /* verify we have something to draw and valid values */ if (v3d->overlay.gpencil_grid_lines < 1) { v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES; } if (v3d->overlay.gpencil_grid_scale == 0.0f) { v3d->overlay.gpencil_grid_scale = 1.0f; } if (v3d->overlay.gpencil_grid_opacity < 0.1f) { v3d->overlay.gpencil_grid_opacity = 0.1f; } UI_GetThemeColor3fv(TH_GRID, col_grid); col_grid[3] = v3d->overlay.gpencil_grid_opacity; /* if use locked axis, copy value */ int axis = v3d->overlay.gpencil_grid_axis; if ((v3d->overlay.gpencil_grid_axis & V3D_GP_GRID_AXIS_LOCK) == 0) { axis = v3d->overlay.gpencil_grid_axis; } else { switch (ts->gp_sculpt.lock_axis) { case GP_LOCKAXIS_X: { axis = V3D_GP_GRID_AXIS_X; break; } case GP_LOCKAXIS_NONE: case GP_LOCKAXIS_Y: { axis = V3D_GP_GRID_AXIS_Y; break; } case GP_LOCKAXIS_Z: { axis = V3D_GP_GRID_AXIS_Z; break; } } } const char *grid_unit = NULL; const int gridlines = v3d->overlay.gpencil_grid_lines; const float grid_scale = v3d->overlay.gpencil_grid_scale * ED_scene_grid_scale(scene, &grid_unit); const float grid = grid_scale; const float space = (grid_scale / gridlines); const uint vertex_len = 2 * (gridlines * 4 + 2); static GPUVertFormat format = { 0 }; static uint pos_id, color_id; if (format.attr_len == 0) { pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); GPU_vertbuf_data_alloc(vbo, vertex_len); int idx = 0; for (int a = 1; a <= gridlines; a++) { const float line = a * space; set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid, -line, axis); idx++; set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid, -line, axis); idx++; set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid, +line, axis); idx++; set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid, +line, axis); idx++; set_grid_point(vbo, idx, col_grid, pos_id, color_id, -line, -grid, axis); idx++; set_grid_point(vbo, idx, col_grid, pos_id, color_id, -line, +grid, axis); idx++; set_grid_point(vbo, idx, col_grid, pos_id, color_id, +line, -grid, axis); idx++; set_grid_point(vbo, idx, col_grid, pos_id, color_id, +line, +grid, axis); idx++; } /* center lines */ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid, 0.0f, axis); idx++; set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid, 0.0f, axis); idx++; set_grid_point(vbo, idx, col_grid, pos_id, color_id, 0.0f, -grid, axis); idx++; set_grid_point(vbo, idx, col_grid, pos_id, color_id, 0.0f, +grid, axis); idx++; return GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO); }