1
1

Compare commits

...

30 Commits

Author SHA1 Message Date
a7910356b0 Mesh Batch Cache: Move index buffer range hack to be more local 2019-07-28 16:29:59 +02:00
b65b93f5d4 Mesh Batch Cache: Refactor: Again
- Use Extract naming convention to name extract functions that fill vbo/ibo
- Separate extract functions into separate file (for clarity)
- Make simpler iter loops to avoid as much overhead as possible
- Separate loose elements looping functions to avoid iteration complexity
  (unfortunately this makes the code more verbose).
- Some iter functions are threadable and tagged as such.
- Add multithreaded iteration for extract functions that supports them.
2019-07-28 15:23:41 +02:00
ef15a45037 GPU: Elements: Put back index tracking in index_buf_set_* functions
There is no threadsafe way of filling the IBOs. So keep filling them
simple and track used indices length.
2019-07-28 15:17:33 +02:00
c3002d51f5 Mesh Batch Cache: Fix threading issue with element buffer objects
Some elements indices can be written by multiple thread at once and
since setting an element is only garantee to be atomic for single verts,
we cannot reliably use GPU_indexbuf_set_line_* in this case.

To avoid this, we create another iteration for the problematic IBOs
2019-07-23 20:02:24 +02:00
c4b27eb46a Cleanup: Remove Printf 2019-07-23 00:10:48 +02:00
76963a7f64 Merge branch 'tmp-batch-cache-cleanup' of git.blender.org:blender into tmp-batch-cache-cleanup 2019-07-23 00:10:02 +02:00
a0ec3b7fd7 Mesh Batch Cache: Fix some threadsafety issue with indices buffers 2019-07-23 00:09:55 +02:00
c63e45c216 Mesh Batch Cache: Fix some threadsafety issue with indices buffers 2019-07-23 00:05:15 +02:00
04a11fa1ba GPU: Make small float normal compression functions inlined 2019-07-22 18:30:10 +02:00
a58548f6f7 Mesh Batch Cache: Fix bitmap test for loose verts 2019-07-22 18:29:31 +02:00
6e06b4f693 Mesh Batch Cache: Add debug timer 2019-07-22 12:48:02 +02:00
e27a478a52 Cleanup: Mesh Batch Cache: Rewrite iterations to prepare for multithreading 2019-07-21 21:27:09 +02:00
f0207be4df Mesh Batch Cache: Speedup: Move the prev edit edge hack for edit uv...
and move it to the only function that needs it: mesh_edituv_data_iter_edit.
2019-07-21 17:38:41 +02:00
c54463b9b3 Mesh Batch Cache: Speedup: Remove the need for memset in index buffer init
Instead of setting the whole IBO to restart index, we only set the restart
indices when we encounter a hidden elem.
2019-07-21 17:24:11 +02:00
7d5e1f61bc Cleanup: Mesh Batch Cache: Remove old unused code 2019-07-21 16:20:10 +02:00
baa34974ef UVEdit: Support Mesh eval cage selection
- Select Vert / Edge / Face support
- TODO : Rect / Lasso / Circle / Loop
2019-07-21 12:01:17 +02:00
711621cac4 Cleanup: Silence warnings 2019-07-21 12:01:17 +02:00
ac0a8fbe71 Mesh Batch Cache: Refactor: Fix subdiv UV edge highligh in vert select mode 2019-07-21 12:01:17 +02:00
f2842babc3 Mesh Batch Cache: Refactor: Fix lnor & vnor display 2019-07-19 18:50:33 +02:00
93f175f279 Mesh Batch Cache: Refactor Part 6
Add back subdiv facedot correct position.
2019-07-19 17:20:46 +02:00
3c95a0c122 Mesh Batch Cache: Refactor Part 5
- Add Vcol support
- Add UV/Tangent support
- Add Orco support
- Add Paint Line Mask support
- Add Adjacency Lines support
- Add EditUV face/line/point/facedot support
- Add EditUV data flag support
- Add EditUV StretchAngle/Area support
- Add Facedots select index support
- Add Weight support
- Add Mesh Analysis support
2019-07-19 17:19:05 +02:00
fcd7de8386 Mesh Batch Cache: Refactor part 4
- Add edge factor support (with less hack + multithread support)
- Add Facedots pos/nor/flag support
- Add Loop normal support
2019-07-19 14:38:32 +02:00
30a68e4d58 Mesh Batch Cache: Refactor part 3
- Add subrange usage for material triangles
- Add loose edges/verts support for Mesh
- Cleanup eval mesh selection
- Add use_hide support
- Add selection index Vbos
- Add edit data vbo
- Add dummy edgefac vbo
2019-07-19 14:38:32 +02:00
ac0d52ee4f Mesh Batch Cache: Refactor part 2
- Add extract_points indices
- Enable tri/line/point extract and pos_nor attrib.
2019-07-19 14:38:32 +02:00
73ca2f702f Mesh Batch Cache: Refactor part 1
- Start refactoring MeshRenderData and mesh_render_data_create_ex
- Add Iter functions
- Add dummy callbacks
- Add some Extract types (not enabled)
2019-07-19 14:38:32 +02:00
520a7ca2f3 Mesh Batch Cache: Refactor start
- Put placeholders vbos/ibos
- Restructure the buffers cache : One cache for final mesh and one for the
  edit mesh cage.
2019-07-19 14:38:32 +02:00
f9e3d7d7eb GPU: Batch: Reverse order of VBO binding
This is to ensure the vbo[0] always has predecence over other VBO.

This is important for overriding attributes by switching vbo binding order.
2019-07-19 14:38:32 +02:00
e02e140ef1 GPU: Vertex Format: Bump max name per attribute to 6
This is to add pos as an alias to UVs.
2019-07-19 14:38:32 +02:00
a97e5be2ae GPU: Add vertex format deinterleaving
This makes it possible to have each attrib use a contiguous portion of the
vertex buffer, making attribute filling much more easy and fast as this is
how they are store in blender Custom Data layers.
2019-07-19 14:38:32 +02:00
7d515f8c90 GPU: Add GPUIndexBuf subrange
This allows to render only a subset of an index buffer.
This is nice as we can render each material surfaces individually and the
whole mesh with the same index buffer.
2019-07-19 14:38:32 +02:00
23 changed files with 4841 additions and 4774 deletions

View File

@@ -480,6 +480,7 @@ void BKE_mesh_calc_poly_center(const struct MPoly *mpoly,
float BKE_mesh_calc_poly_area(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray);
float BKE_mesh_calc_poly_uv_area(const struct MPoly *mpoly, const struct MLoopUV *uv_array);
void BKE_mesh_calc_poly_angles(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray,

View File

@@ -2378,6 +2378,24 @@ float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const
}
}
float BKE_mesh_calc_poly_uv_area(const MPoly *mpoly, const MLoopUV *uv_array)
{
int i, l_iter = mpoly->loopstart;
float area;
float(*vertexcos)[2] = BLI_array_alloca(vertexcos, (size_t)mpoly->totloop);
/* pack vertex cos into an array for area_poly_v2 */
for (i = 0; i < mpoly->totloop; i++, l_iter++) {
copy_v2_v2(vertexcos[i], uv_array[l_iter].uv);
}
/* finally calculate the area */
area = area_poly_v2((const float(*)[2])vertexcos, (unsigned int)mpoly->totloop);
return area;
}
/**
* Calculate the volume and volume-weighted centroid of the volume
* formed by the polygon and the origin.

View File

@@ -52,6 +52,7 @@ set(SRC
intern/draw_anim_viz.c
intern/draw_armature.c
intern/draw_cache.c
intern/draw_cache_extract_mesh.c
intern/draw_cache_impl_curve.c
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_lattice.c
@@ -130,6 +131,7 @@ set(SRC
DRW_engine.h
intern/DRW_render.h
intern/draw_cache.h
intern/draw_cache_extract.h
intern/draw_cache_impl.h
intern/draw_cache_inline.h
intern/draw_common.h

View File

@@ -4033,7 +4033,7 @@ void drw_batch_cache_validate(Object *ob)
void drw_batch_cache_generate_requested(Object *ob)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const ToolSettings *ts = draw_ctx->scene->toolsettings;
const Scene *scene = draw_ctx->scene;
const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
const bool is_paint_mode = ELEM(
@@ -4047,13 +4047,13 @@ void drw_batch_cache_generate_requested(Object *ob)
struct Mesh *mesh_eval = ob->runtime.mesh_eval;
switch (ob->type) {
case OB_MESH:
DRW_mesh_batch_cache_create_requested(ob, (Mesh *)ob->data, ts, is_paint_mode, use_hide);
DRW_mesh_batch_cache_create_requested(ob, (Mesh *)ob->data, scene, is_paint_mode, use_hide);
break;
case OB_CURVE:
case OB_FONT:
case OB_SURF:
if (mesh_eval) {
DRW_mesh_batch_cache_create_requested(ob, mesh_eval, ts, is_paint_mode, use_hide);
DRW_mesh_batch_cache_create_requested(ob, mesh_eval, scene, is_paint_mode, use_hide);
}
DRW_curve_batch_cache_create_requested(ob);
break;

View File

@@ -0,0 +1,244 @@
/*
* 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.
*
* Copyright 2019, Blender Foundation.
*/
/** \file
* \ingroup draw
*/
#ifndef __DRAW_CACHE_EXTRACT_MESH_H__
#define __DRAW_CACHE_EXTRACT_MESH_H__
/* Vertex Group Selection and display options */
typedef struct DRW_MeshWeightState {
int defgroup_active;
int defgroup_len;
short flags;
char alert_mode;
/* Set of all selected bones for Multipaint. */
bool *defgroup_sel; /* [defgroup_len] */
int defgroup_sel_count;
} DRW_MeshWeightState;
/* DRW_MeshWeightState.flags */
enum {
DRW_MESH_WEIGHT_STATE_MULTIPAINT = (1 << 0),
DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE = (1 << 1),
};
typedef struct DRW_MeshCDMask {
uint32_t uv : 8;
uint32_t tan : 8;
uint32_t vcol : 8;
uint32_t orco : 1;
uint32_t tan_orco : 1;
} DRW_MeshCDMask;
typedef enum eMRIterType {
MR_ITER_LOOPTRI = 1 << 0,
MR_ITER_LOOP = 1 << 1,
MR_ITER_LEDGE = 1 << 2,
MR_ITER_LVERT = 1 << 3,
} eMRIterType;
typedef enum eMRDataType {
MR_DATA_POLY_NOR = 1 << 1,
MR_DATA_LOOP_NOR = 1 << 2,
MR_DATA_LOOPTRI = 1 << 3,
} eMRDataType;
typedef enum eMRExtractType {
MR_EXTRACT_BMESH,
MR_EXTRACT_MAPPED,
MR_EXTRACT_MESH,
} eMRExtractType;
BLI_INLINE int mesh_render_mat_len_get(Mesh *me)
{
return MAX2(1, me->totcol);
}
typedef struct MeshBufferCache {
/* Every VBO below contains at least enough
* data for every loops in the mesh (except fdots).
* For some VBOs, it extends to (in this exact order) :
* loops + loose_edges*2 + loose_verts */
struct {
GPUVertBuf *pos_nor; /* extend */
GPUVertBuf *lnor; /* extend */
GPUVertBuf *edge_fac; /* extend */
GPUVertBuf *weights; /* extend */
GPUVertBuf *uv_tan;
GPUVertBuf *vcol;
GPUVertBuf *orco;
/* Only for edit mode. */
GPUVertBuf *edit_data; /* extend */
GPUVertBuf *edituv_data;
GPUVertBuf *stretch_area;
GPUVertBuf *stretch_angle;
GPUVertBuf *mesh_analysis;
GPUVertBuf *fdots_pos;
GPUVertBuf *fdots_nor;
GPUVertBuf *fdots_uv;
// GPUVertBuf *fdots_edit_data; /* inside fdots_nor for now. */
GPUVertBuf *fdots_edituv_data;
/* Selection */
GPUVertBuf *vert_idx; /* extend */
GPUVertBuf *edge_idx; /* extend */
GPUVertBuf *poly_idx;
GPUVertBuf *fdot_idx;
} vbo;
/* Index Buffers:
* Only need to be updated when topology changes. */
struct {
/* Indices to vloops. */
GPUIndexBuf *tris; /* Ordered per material. */
GPUIndexBuf *lines; /* Loose edges last. */
GPUIndexBuf *points;
GPUIndexBuf *fdots;
/* 3D overlays. */
GPUIndexBuf *lines_paint_mask; /* no loose edges. */
GPUIndexBuf *lines_adjacency;
/* Uv overlays. (visibility can differ from 3D view) */
GPUIndexBuf *edituv_tris;
GPUIndexBuf *edituv_lines;
GPUIndexBuf *edituv_points;
GPUIndexBuf *edituv_fdots;
} ibo;
} MeshBufferCache;
typedef enum DRWBatchFlag {
MBC_SURFACE = (1 << 0),
MBC_SURFACE_WEIGHTS = (1 << 1),
MBC_EDIT_TRIANGLES = (1 << 2),
MBC_EDIT_VERTICES = (1 << 3),
MBC_EDIT_EDGES = (1 << 4),
MBC_EDIT_VNOR = (1 << 5),
MBC_EDIT_LNOR = (1 << 6),
MBC_EDIT_FACEDOTS = (1 << 7),
MBC_EDIT_MESH_ANALYSIS = (1 << 8),
MBC_EDITUV_FACES_STRECH_AREA = (1 << 9),
MBC_EDITUV_FACES_STRECH_ANGLE = (1 << 10),
MBC_EDITUV_FACES = (1 << 11),
MBC_EDITUV_EDGES = (1 << 12),
MBC_EDITUV_VERTS = (1 << 13),
MBC_EDITUV_FACEDOTS = (1 << 14),
MBC_EDIT_SELECTION_VERTS = (1 << 15),
MBC_EDIT_SELECTION_EDGES = (1 << 16),
MBC_EDIT_SELECTION_FACES = (1 << 17),
MBC_EDIT_SELECTION_FACEDOTS = (1 << 18),
MBC_ALL_VERTS = (1 << 19),
MBC_ALL_EDGES = (1 << 20),
MBC_LOOSE_EDGES = (1 << 21),
MBC_EDGE_DETECTION = (1 << 22),
MBC_WIRE_EDGES = (1 << 23),
MBC_WIRE_LOOPS = (1 << 24),
MBC_WIRE_LOOPS_UVS = (1 << 25),
MBC_SURF_PER_MAT = (1 << 26),
} DRWBatchFlag;
#define MBC_EDITUV \
(MBC_EDITUV_FACES_STRECH_AREA | MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | \
MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \
for (MeshBufferCache *mbc = &batch_cache->final; \
mbc == &batch_cache->final || mbc == &batch_cache->cage; \
mbc = (mbc == &batch_cache->final) ? &batch_cache->cage : NULL)
typedef struct MeshBatchCache {
MeshBufferCache final, cage;
struct {
/* Surfaces / Render */
GPUBatch *surface;
GPUBatch *surface_weights;
/* Edit mode */
GPUBatch *edit_triangles;
GPUBatch *edit_vertices;
GPUBatch *edit_edges;
GPUBatch *edit_vnor;
GPUBatch *edit_lnor;
GPUBatch *edit_fdots;
GPUBatch *edit_mesh_analysis;
/* Edit UVs */
GPUBatch *edituv_faces_strech_area;
GPUBatch *edituv_faces_strech_angle;
GPUBatch *edituv_faces;
GPUBatch *edituv_edges;
GPUBatch *edituv_verts;
GPUBatch *edituv_fdots;
/* Edit selection */
GPUBatch *edit_selection_verts;
GPUBatch *edit_selection_edges;
GPUBatch *edit_selection_faces;
GPUBatch *edit_selection_fdots;
/* Common display / Other */
GPUBatch *all_verts;
GPUBatch *all_edges;
GPUBatch *loose_edges;
GPUBatch *edge_detection;
GPUBatch *wire_edges; /* Individual edges with face normals. */
GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */
GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */
} batch;
GPUBatch **surface_per_mat;
/* arrays of bool uniform names (and value) that will be use to
* set srgb conversion for auto attributes.*/
char *auto_layer_names;
int *auto_layer_is_srgb;
int auto_layer_len;
DRWBatchFlag batch_requested;
DRWBatchFlag batch_ready;
/* settings to determine if cache is invalid */
int edge_len;
int tri_len;
int poly_len;
int vert_len;
int mat_len;
bool is_dirty; /* Instantly invalidates cache, skipping mesh check */
bool is_editmode;
bool is_uvsyncsel;
struct DRW_MeshWeightState weight_state;
DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
int lastmatch;
/* Valid only if edge_detection is up to date. */
bool is_manifold;
bool no_loose_wire;
} MeshBatchCache;
void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
MeshBufferCache mbc,
Mesh *me,
const bool do_final,
const bool use_subsurf_fdots,
const DRW_MeshCDMask *cd_layer_used,
const ToolSettings *ts,
const bool use_hide);
#endif /* __DRAW_CACHE_EXTRACT_MESH_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -119,7 +119,7 @@ struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt);
/* Mesh */
void DRW_mesh_batch_cache_create_requested(struct Object *ob,
struct Mesh *me,
const struct ToolSettings *ts,
const struct Scene *scene,
const bool is_paint_mode,
const bool use_hide);
@@ -143,6 +143,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(struct Mesh *me);
/* edit-mesh selection */

File diff suppressed because it is too large Load Diff

View File

@@ -2772,7 +2772,7 @@ void DRW_draw_select_id_object(Scene *scene,
if (use_faceselect && draw_facedot) {
geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(me);
}
DRW_mesh_batch_cache_create_requested(ob, me, NULL, false, true);
DRW_mesh_batch_cache_create_requested(ob, me, scene, false, true);
draw_mesh_face(geom_faces, initial_offset, use_faceselect, world_clip_planes);
@@ -2824,7 +2824,7 @@ void DRW_draw_select_id_object(Scene *scene,
((ob->mode & OB_MODE_WEIGHT_PAINT) || (ob->mode & OB_MODE_VERTEX_PAINT))) {
GPUBatch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me_eval);
DRW_mesh_batch_cache_create_requested(ob, me_eval, NULL, false, true);
DRW_mesh_batch_cache_create_requested(ob, me_eval, scene, false, true);
/* Only draw faces to mask out verts, we don't want their selection ID's. */
draw_mesh_face(geom_faces, 0, false, world_clip_planes);
@@ -2835,7 +2835,7 @@ void DRW_draw_select_id_object(Scene *scene,
}
else {
const bool use_hide = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL);
DRW_mesh_batch_cache_create_requested(ob, me_eval, NULL, false, use_hide);
DRW_mesh_batch_cache_create_requested(ob, me_eval, scene, false, use_hide);
draw_mesh_face(geom_faces, initial_offset, true, world_clip_planes);

View File

@@ -727,7 +727,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
}
if (vnormals_do) {
geom = DRW_mesh_batch_cache_get_edit_vertices(ob->data);
geom = DRW_mesh_batch_cache_get_edit_vnors(ob->data);
DRW_shgroup_call_no_cull(g_data->vnormals_shgrp, geom, ob);
}
if (lnormals_do) {

View File

@@ -488,6 +488,7 @@ static bool uv_edge_compare(const void *a, const void *b)
static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event)
{
Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
ToolSettings *ts = scene->toolsettings;
@@ -554,7 +555,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
UvElement *element;
UvNearestHit hit = UV_NEAREST_HIT_INIT;
Image *ima = CTX_data_edit_image(C);
uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit);
uv_find_nearest_vert(depsgraph, scene, ima, obedit, co, 0.0f, &hit);
element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
island_index = element->island;

View File

@@ -163,13 +163,13 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
static void uvedit_get_batches(Object *ob,
SpaceImage *sima,
const ToolSettings *ts,
const Scene *scene,
GPUBatch **faces,
GPUBatch **edges,
GPUBatch **verts,
GPUBatch **facedots)
{
int drawfaces = draw_uvs_face_check(ts);
int drawfaces = draw_uvs_face_check(scene->toolsettings);
const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0;
@@ -197,7 +197,7 @@ static void uvedit_get_batches(Object *ob,
*faces = NULL;
}
DRW_mesh_batch_cache_create_requested(ob, ob->data, ts, false, false);
DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false);
}
static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
@@ -212,7 +212,7 @@ static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
DRW_mesh_batch_cache_validate(me);
GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me);
DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false);
DRW_mesh_batch_cache_create_requested(eval_ob, me, scene, false, false);
if (edges) {
GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR);
@@ -235,7 +235,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
DRW_mesh_batch_cache_validate(me);
GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me);
DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false);
DRW_mesh_batch_cache_create_requested(eval_ob, me, scene, false, false);
GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UV_UNIFORM_COLOR);
GPU_batch_uniform_4fv(geom, "color", col);
@@ -300,7 +300,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
}
}
uvedit_get_batches(eval_ob, sima, ts, &faces, &edges, &verts, &facedots);
uvedit_get_batches(eval_ob, sima, scene, &faces, &edges, &verts, &facedots);
bool interpedges;
bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;

View File

@@ -57,13 +57,15 @@ typedef struct UvNearestHit {
.dist_sq = FLT_MAX, \
}
bool uv_find_nearest_vert(struct Scene *scene,
bool uv_find_nearest_vert(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Image *ima,
struct Object *obedit,
const float co[2],
const float penalty_dist,
struct UvNearestHit *hit_final);
bool uv_find_nearest_vert_multi(struct Scene *scene,
bool uv_find_nearest_vert_multi(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Image *ima,
struct Object **objects,
const uint objects_len,
@@ -71,24 +73,28 @@ bool uv_find_nearest_vert_multi(struct Scene *scene,
const float penalty_dist,
struct UvNearestHit *hit_final);
bool uv_find_nearest_edge(struct Scene *scene,
bool uv_find_nearest_edge(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Image *ima,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_edge_multi(struct Scene *scene,
bool uv_find_nearest_edge_multi(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_face(struct Scene *scene,
bool uv_find_nearest_face(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Image *ima,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_face_multi(struct Scene *scene,
bool uv_find_nearest_face_multi(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Image *ima,
struct Object **objects,
const uint objects_len,

View File

@@ -56,6 +56,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -606,6 +607,18 @@ void uv_poly_center(BMFace *f, float r_cent[2], const int cd_loop_uv_offset)
mul_v2_fl(r_cent, 1.0f / (float)f->len);
}
static void uv_mpoly_center(const MPoly *mpoly, const MLoopUV *mloopuv, float r_cent[2])
{
zero_v2(r_cent);
for (int i = 0; i < mpoly->totloop; i++) {
const MLoopUV *luv = &mloopuv[mpoly->loopstart + i];
add_v2_v2(r_cent, luv->uv);
}
mul_v2_fl(r_cent, 1.0f / (float)mpoly->totloop);
}
void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
{
int i;
@@ -753,8 +766,12 @@ bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], c
/** \name Find Nearest Elements
* \{ */
bool uv_find_nearest_edge(
Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit)
bool uv_find_nearest_edge(Depsgraph *depsgraph,
Scene *scene,
Image *ima,
Object *obedit,
const float co[2],
UvNearestHit *hit)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
@@ -766,35 +783,85 @@ bool uv_find_nearest_edge(
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
/* (fclem) Is it garanteed that obedit_eval will be updated? */
Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
if (!em_eval->mesh_eval_cage || em_eval->mesh_eval_cage->runtime.is_original) {
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
if (dist_test_sq < hit->dist_sq) {
hit->efa = efa;
hit->l = l;
hit->luv = luv;
hit->luv_next = luv_next;
hit->lindex = i;
hit->dist_sq = dist_test_sq;
found = true;
}
}
}
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
}
else {
Mesh *me = em_eval->mesh_eval_cage;
const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
BM_mesh_elem_table_ensure(em->bm, BM_FACE | BM_EDGE);
if (dist_test_sq < hit->dist_sq) {
hit->efa = efa;
int *p_origindex = CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
int *e_origindex = CustomData_get_layer(&me->edata, CD_ORIGINDEX);
hit->l = l;
hit->luv = luv;
hit->luv_next = luv_next;
hit->lindex = i;
MLoopUV *mluv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
hit->dist_sq = dist_test_sq;
found = true;
MPoly *mpoly = me->mpoly;
for (int p = 0; p < me->totpoly; p++, mpoly++) {
if (p_origindex[p] == ORIGINDEX_NONE) {
continue;
}
efa = BM_face_at_index(em->bm, p_origindex[p]);
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
for (i = 0; i < mpoly->totloop; i++) {
MLoop *mloop = &me->mloop[mpoly->loopstart + i];
if (e_origindex[mloop->e] == ORIGINDEX_NONE) {
continue;
}
luv = &mluv[mpoly->loopstart + i];
luv_next = &mluv[mpoly->loopstart + ((i + 1) % mpoly->totloop)];
const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
if (dist_test_sq < hit->dist_sq) {
BMEdge *eed = BM_edge_at_index(em->bm, e_origindex[mloop->e]);
hit->efa = efa;
hit->l = BM_face_edge_share_loop(efa, eed);
hit->luv = luv;
hit->luv_next = luv_next;
hit->lindex = i;
hit->dist_sq = dist_test_sq;
found = true;
}
}
}
}
return found;
}
bool uv_find_nearest_edge_multi(Scene *scene,
bool uv_find_nearest_edge_multi(Depsgraph *depsgraph,
Scene *scene,
Image *ima,
Object **objects,
const uint objects_len,
@@ -804,7 +871,7 @@ bool uv_find_nearest_edge_multi(Scene *scene,
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
if (uv_find_nearest_edge(depsgraph, scene, ima, obedit, co, hit_final)) {
hit_final->ob = obedit;
found = true;
}
@@ -812,8 +879,12 @@ bool uv_find_nearest_edge_multi(Scene *scene,
return found;
}
bool uv_find_nearest_face(
Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final)
bool uv_find_nearest_face(Depsgraph *depsgraph,
Scene *scene,
Image *ima,
Object *obedit,
const float co[2],
UvNearestHit *hit_final)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
bool found = false;
@@ -823,28 +894,94 @@ bool uv_find_nearest_face(
/* this will fill in hit.vert1 and hit.vert2 */
float dist_sq_init = hit_final->dist_sq;
UvNearestHit hit = *hit_final;
if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
if (uv_find_nearest_edge(depsgraph, scene, ima, obedit, co, &hit)) {
hit.dist_sq = dist_sq_init;
hit.l = NULL;
hit.luv = hit.luv_next = NULL;
BMIter iter;
/* (fclem) Is it garanteed that obedit_eval will be updated? */
Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
BMFace *efa;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
if (!em_eval->mesh_eval_cage || em_eval->mesh_eval_cage->runtime.is_original) {
BMIter iter;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
float cent[2];
uv_poly_center(efa, cent, cd_loop_uv_offset);
const float dist_test_sq = len_squared_v2v2(co, cent);
if (dist_test_sq < hit.dist_sq) {
hit.efa = efa;
hit.dist_sq = dist_test_sq;
found = true;
}
}
}
else {
Mesh *me = em_eval->mesh_eval_cage;
float cent[2];
uv_poly_center(efa, cent, cd_loop_uv_offset);
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
const float dist_test_sq = len_squared_v2v2(co, cent);
int *p_origindex = CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
if (dist_test_sq < hit.dist_sq) {
hit.efa = efa;
hit.dist_sq = dist_test_sq;
found = true;
MLoopUV *mluv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
if (modifiers_usesSubsurfFacedots(scene, obedit)) {
const MPoly *mpoly = me->mpoly;
for (int p = 0; p < me->totpoly; p++, mpoly++) {
if (p_origindex[p] == ORIGINDEX_NONE) {
continue;
}
efa = BM_face_at_index(em->bm, p_origindex[p]);
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
for (int i = 0; i < mpoly->totloop; i++) {
MLoop *mloop = &me->mloop[mpoly->loopstart + i];
MVert *mvert = &me->mvert[mloop->v];
if ((mvert->flag & ME_VERT_FACEDOT) == 0) {
continue;
}
const float dist_test_sq = len_squared_v2v2(co, mluv[mpoly->loopstart + i].uv);
if (dist_test_sq < hit.dist_sq) {
hit.efa = efa;
hit.dist_sq = dist_test_sq;
found = true;
}
}
}
}
else {
const MPoly *mpoly = me->mpoly;
for (int p = 0; p < me->totpoly; p++, mpoly++) {
if (p_origindex[p] == ORIGINDEX_NONE) {
continue;
}
efa = BM_face_at_index(em->bm, p_origindex[p]);
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
float cent[2];
uv_mpoly_center(mpoly, mluv, cent);
const float dist_test_sq = len_squared_v2v2(co, cent);
if (dist_test_sq < hit.dist_sq) {
hit.efa = efa;
hit.dist_sq = dist_test_sq;
found = true;
}
}
}
}
}
@@ -854,7 +991,8 @@ bool uv_find_nearest_face(
return found;
}
bool uv_find_nearest_face_multi(Scene *scene,
bool uv_find_nearest_face_multi(Depsgraph *depsgraph,
Scene *scene,
Image *ima,
Object **objects,
const uint objects_len,
@@ -864,7 +1002,7 @@ bool uv_find_nearest_face_multi(Scene *scene,
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
if (uv_find_nearest_face(depsgraph, scene, ima, obedit, co, hit_final)) {
hit_final->ob = obedit;
found = true;
}
@@ -882,7 +1020,8 @@ static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_
(line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
}
bool uv_find_nearest_vert(Scene *scene,
bool uv_find_nearest_vert(Depsgraph *depsgraph,
Scene *scene,
Image *ima,
Object *obedit,
float const co[2],
@@ -894,7 +1033,7 @@ bool uv_find_nearest_vert(Scene *scene,
/* this will fill in hit.vert1 and hit.vert2 */
float dist_sq_init = hit_final->dist_sq;
UvNearestHit hit = *hit_final;
if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
if (uv_find_nearest_edge(depsgraph, scene, ima, obedit, co, &hit)) {
hit.dist_sq = dist_sq_init;
hit.l = NULL;
@@ -902,46 +1041,112 @@ bool uv_find_nearest_vert(Scene *scene,
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMIter iter;
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
/* (fclem) Is it garanteed that obedit_eval will be updated? */
Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
if (!em_eval->mesh_eval_cage || em_eval->mesh_eval_cage->runtime.is_original) {
BMIter iter;
BMIter liter;
BMLoop *l;
int i;
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
float dist_test_sq;
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
dist_test_sq = SQUARE(dist_test_sq);
}
else {
dist_test_sq = len_squared_v2v2(co, luv->uv);
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
if (dist_test_sq <= hit.dist_sq) {
if (dist_test_sq == hit.dist_sq) {
if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
continue;
}
BMIter liter;
BMLoop *l;
int i;
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
float dist_test_sq;
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
dist_test_sq = SQUARE(dist_test_sq);
}
else {
dist_test_sq = len_squared_v2v2(co, luv->uv);
}
hit.dist_sq = dist_test_sq;
if (dist_test_sq <= hit.dist_sq) {
if (dist_test_sq == hit.dist_sq) {
if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
continue;
}
}
hit.l = l;
hit.luv = luv;
hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
hit.efa = efa;
hit.lindex = i;
found = true;
hit.dist_sq = dist_test_sq;
hit.l = l;
hit.luv = luv;
hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
hit.efa = efa;
hit.lindex = i;
found = true;
}
}
}
}
else {
Mesh *me = em_eval->mesh_eval_cage;
BM_mesh_elem_table_ensure(em->bm, BM_FACE | BM_EDGE);
int *p_origindex = CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
int *e_origindex = CustomData_get_layer(&me->edata, CD_ORIGINDEX);
MLoopUV *mluv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
MPoly *mpoly = me->mpoly;
for (int p = 0; p < me->totpoly; p++, mpoly++) {
if (p_origindex[p] == ORIGINDEX_NONE) {
continue;
}
efa = BM_face_at_index(em->bm, p_origindex[p]);
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
for (int i = 0; i < mpoly->totloop; i++) {
MLoop *mloop = &me->mloop[mpoly->loopstart + i];
if (e_origindex[mloop->e] == ORIGINDEX_NONE) {
continue;
}
MLoopUV *luv = &mluv[mpoly->loopstart + i];
MLoopUV *luv_next = &mluv[mpoly->loopstart + ((i + 1) % mpoly->totloop)];
BMEdge *eed = BM_edge_at_index(em->bm, e_origindex[mloop->e]);
BMLoop *l = BM_face_edge_share_loop(efa, eed);
float dist_test_sq;
if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
dist_test_sq = SQUARE(dist_test_sq);
}
else {
dist_test_sq = len_squared_v2v2(co, luv->uv);
}
if (dist_test_sq <= hit.dist_sq) {
/* FIXME this is testing against original coord, not deformed cage. */
if (dist_test_sq == hit.dist_sq) {
if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
continue;
}
}
hit.dist_sq = dist_test_sq;
hit.l = l;
hit.luv = luv;
hit.luv_next = luv_next;
hit.efa = efa;
hit.lindex = i;
found = true;
}
}
}
}
@@ -954,7 +1159,8 @@ bool uv_find_nearest_vert(Scene *scene,
return found;
}
bool uv_find_nearest_vert_multi(Scene *scene,
bool uv_find_nearest_vert_multi(Depsgraph *depsgraph,
Scene *scene,
Image *ima,
Object **objects,
const uint objects_len,
@@ -965,7 +1171,7 @@ bool uv_find_nearest_vert_multi(Scene *scene,
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
if (uv_find_nearest_vert(depsgraph, scene, ima, obedit, co, penalty_dist, hit_final)) {
hit_final->ob = obedit;
found = true;
}
@@ -1274,9 +1480,9 @@ static void uv_select_linked_multi(Scene *scene,
BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
/* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
* this made *every* projection split the island into front/back islands.
* Keep 'use_winding' to false, see: T50970.
/* Note, we had 'use winding' so we don't consider overlapping islands as connected, see
* T44320 this made *every* projection split the island into front/back islands. Keep
* 'use_winding' to false, see: T50970.
*
* Better solve this by having a delimit option for select-linked operator,
* keeping island-select working as is. */
@@ -2513,12 +2719,12 @@ static int uv_mouse_select_multi(bContext *C,
/* find nearest element */
if (loop) {
/* find edge */
found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
found_item = uv_find_nearest_edge_multi(depsgraph, scene, ima, objects, objects_len, co, &hit);
}
else if (selectmode == UV_SELECT_VERTEX) {
/* find vertex */
found_item = uv_find_nearest_vert_multi(
scene, ima, objects, objects_len, co, penalty_dist, &hit);
depsgraph, scene, ima, objects, objects_len, co, penalty_dist, &hit);
found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
if (found_item) {
@@ -2535,7 +2741,7 @@ static int uv_mouse_select_multi(bContext *C,
}
else if (selectmode == UV_SELECT_EDGE) {
/* find edge */
found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
found_item = uv_find_nearest_edge_multi(depsgraph, scene, ima, objects, objects_len, co, &hit);
found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
if (found_item) {
@@ -2554,7 +2760,7 @@ static int uv_mouse_select_multi(bContext *C,
}
else if (selectmode == UV_SELECT_FACE) {
/* find face */
found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit);
found_item = uv_find_nearest_face_multi(depsgraph, scene, ima, objects, objects_len, co, &hit);
found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
if (found_item) {
@@ -2578,7 +2784,7 @@ static int uv_mouse_select_multi(bContext *C,
}
}
else if (selectmode == UV_SELECT_ISLAND) {
found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
found_item = uv_find_nearest_edge_multi(depsgraph, scene, ima, objects, objects_len, co, &hit);
found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
}
@@ -2892,6 +3098,7 @@ static void UV_OT_select_loop(wmOperatorType *ot)
static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
{
Depsgraph *depsgraph = CTX_data_depsgraph(C);
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -2936,7 +3143,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
RNA_float_get_array(op->ptr, "location", co);
}
if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
if (!uv_find_nearest_edge_multi(depsgraph, scene, ima, objects, objects_len, co, &hit)) {
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}

View File

@@ -2550,11 +2550,13 @@ static StitchState *stitch_select(bContext *C,
UvNearestHit hit = UV_NEAREST_HIT_INIT;
ARegion *ar = CTX_wm_region(C);
Image *ima = CTX_data_edit_image(C);
Depsgraph *depsgraph = CTX_data_depsgraph(C);
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
if (ssc->mode == STITCH_VERT) {
if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
if (uv_find_nearest_vert_multi(
depsgraph, scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
/* Add vertex to selection, deselect all common uv's of vert other than selected and
* update the preview. This behavior was decided so that you can do stuff like deselect
* the opposite stitchable vertex and the initial still gets deselected */
@@ -2575,7 +2577,8 @@ static StitchState *stitch_select(bContext *C,
return state;
}
}
else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) {
else if (uv_find_nearest_edge_multi(
depsgraph, scene, ima, ssc->objects, ssc->objects_len, co, &hit)) {
/* find StitchState from hit->ob */
StitchState *state = NULL;
for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {

View File

@@ -40,7 +40,7 @@ typedef enum {
GPU_BATCH_READY_TO_DRAW,
} GPUBatchPhase;
#define GPU_BATCH_VBO_MAX_LEN 4
#define GPU_BATCH_VBO_MAX_LEN 5
#define GPU_BATCH_VAO_STATIC_LEN 3
#define GPU_BATCH_VAO_DYN_ALLOC_COUNT 16
@@ -114,6 +114,7 @@ void GPU_batch_vao_cache_clear(GPUBatch *);
void GPU_batch_callback_free_set(GPUBatch *, void (*callback)(GPUBatch *, void *), void *);
void GPU_batch_instbuf_set(GPUBatch *, GPUVertBuf *, bool own_vbo); /* Instancing */
void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo);
int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);

View File

@@ -36,14 +36,19 @@ typedef enum {
} GPUIndexBufType;
typedef struct GPUIndexBuf {
uint index_start;
uint index_len;
bool is_subrange;
#if GPU_TRACK_INDEX_RANGE
GPUIndexBufType index_type;
uint32_t gl_index_type;
uint base_index;
#endif
uint32_t ibo_id; /* 0 indicates not yet sent to VRAM */
void *data; /* non-NULL indicates not yet sent to VRAM */
union {
void *data; /* non-NULL indicates not yet sent to VRAM */
struct GPUIndexBuf *src; /* if is_subrange is true, this is the source buffer. */
};
} GPUIndexBuf;
void GPU_indexbuf_use(GPUIndexBuf *);
@@ -71,9 +76,21 @@ void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *, uint v1, uint v2);
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3);
void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3, uint v4);
void GPU_indexbuf_set_point_vert(GPUIndexBufBuilder *builder, uint elem, uint v1);
void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2);
void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3);
/* Skip primitive rendering at the given index. */
void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem);
void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem);
void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem);
GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *);
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *);
/* Create a subrange of an existing indexbuffer. */
GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *ibo, uint start, uint length);
void GPU_indexbuf_discard(GPUIndexBuf *);
int GPU_indexbuf_primitive_len(GPUPrimType prim_type);

View File

@@ -31,7 +31,7 @@
#include "BLI_assert.h"
#define GPU_VERT_ATTR_MAX_LEN 16
#define GPU_VERT_ATTR_MAX_NAMES 5
#define GPU_VERT_ATTR_MAX_NAMES 6
#define GPU_VERT_ATTR_NAME_AVERAGE_LEN 11
#define GPU_VERT_ATTR_NAMES_BUF_LEN ((GPU_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GPU_VERT_ATTR_MAX_LEN)
@@ -88,6 +88,8 @@ typedef struct GPUVertFormat {
uint packed : 1;
/** Current offset in names[]. */
uint name_offset : 8;
/** Store each attrib in one contiguous buffer region. */
uint deinterleaved : 1;
GPUVertAttr attrs[GPU_VERT_ATTR_MAX_LEN];
char names[GPU_VERT_ATTR_NAMES_BUF_LEN];
@@ -104,6 +106,8 @@ uint GPU_vertformat_attr_add(
GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode);
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias);
void GPU_vertformat_deinterleave(GPUVertFormat *format);
int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name);
BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format,
@@ -122,7 +126,59 @@ typedef struct GPUPackedNormal {
int w : 2; /* 0 by default, can manually set to { -2, -1, 0, 1 } */
} GPUPackedNormal;
GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3]);
GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3]);
/* OpenGL ES packs in a different order as desktop GL but component conversion is the same.
* Of the code here, only struct GPUPackedNormal needs to change. */
#define SIGNED_INT_10_MAX 511
#define SIGNED_INT_10_MIN -512
BLI_INLINE int clampi(int x, int min_allowed, int max_allowed)
{
#if TRUST_NO_ONE
assert(min_allowed <= max_allowed);
#endif
if (x < min_allowed) {
return min_allowed;
}
else if (x > max_allowed) {
return max_allowed;
}
else {
return x;
}
}
BLI_INLINE int quantize(float x)
{
int qx = x * 511.0f;
return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX);
}
BLI_INLINE int convert_i16(short x)
{
/* 16-bit signed --> 10-bit signed */
/* TODO: round? */
return x >> 6;
}
BLI_INLINE GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3])
{
GPUPackedNormal n = {
.x = quantize(data[0]),
.y = quantize(data[1]),
.z = quantize(data[2]),
};
return n;
}
BLI_INLINE GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3])
{
GPUPackedNormal n = {
.x = convert_i16(data[0]),
.y = convert_i16(data[1]),
.z = convert_i16(data[2]),
};
return n;
}
#endif /* __GPU_VERTEX_FORMAT_H__ */

View File

@@ -181,6 +181,25 @@ void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
}
}
void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo)
{
BLI_assert(elem != NULL);
/* redo the bindings */
GPU_batch_vao_cache_clear(batch);
if (batch->elem != NULL && (batch->owns_flag & GPU_BATCH_OWNS_INDEX)) {
GPU_indexbuf_discard(batch->elem);
}
batch->elem = elem;
if (own_ibo) {
batch->owns_flag |= GPU_BATCH_OWNS_INDEX;
}
else {
batch->owns_flag &= ~GPU_BATCH_OWNS_INDEX;
}
}
/* Returns the index of verts in the batch. */
int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
{
@@ -361,13 +380,23 @@ static void create_bindings(GPUVertBuf *verts,
const GPUVertFormat *format = &verts->format;
const uint attr_len = format->attr_len;
const uint stride = format->stride;
uint stride = format->stride;
uint offset = 0;
GPU_vertbuf_use(verts);
for (uint a_idx = 0; a_idx < attr_len; ++a_idx) {
const GPUVertAttr *a = &format->attrs[a_idx];
const GLvoid *pointer = (const GLubyte *)0 + a->offset + v_first * stride;
if (format->deinterleaved) {
offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].sz) * verts->vertex_len;
stride = a->sz;
}
else {
offset = a->offset;
}
const GLvoid *pointer = (const GLubyte *)0 + offset + v_first * stride;
for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) {
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
@@ -418,8 +447,11 @@ static void create_bindings(GPUVertBuf *verts,
static void batch_update_program_bindings(GPUBatch *batch, uint v_first)
{
for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN && batch->verts[v] != NULL; ++v) {
create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
/* Reverse order so first vbos have more prevalence (in term of attrib override). */
for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; --v) {
if (batch->verts[v] != NULL) {
create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
}
}
if (batch->inst) {
create_bindings(batch->inst, batch->interface, v_first, true);
@@ -549,10 +581,10 @@ static void *elem_offset(const GPUIndexBuf *el, int v_first)
{
#if GPU_TRACK_INDEX_RANGE
if (el->index_type == GPU_INDEX_U16) {
return (GLushort *)0 + v_first;
return (GLushort *)0 + v_first + el->index_start;
}
#endif
return (GLuint *)0 + v_first;
return (GLuint *)0 + v_first + el->index_start;
}
/* Use when drawing with GPU_batch_draw_advanced */

View File

@@ -162,6 +162,100 @@ void GPU_indexbuf_add_line_adj_verts(
GPU_indexbuf_add_generic_vert(builder, v4);
}
void GPU_indexbuf_set_point_vert(GPUIndexBufBuilder *builder, uint elem, uint v1)
{
BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
BLI_assert(elem < builder->max_index_len);
builder->data[elem++] = v1;
if (builder->index_len < elem) {
builder->index_len = elem;
}
}
void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2)
{
BLI_assert(builder->prim_type == GPU_PRIM_LINES);
BLI_assert(v1 != v2);
BLI_assert(v1 <= builder->max_allowed_index);
BLI_assert(v2 <= builder->max_allowed_index);
BLI_assert((elem + 1) * 2 <= builder->max_index_len);
uint idx = elem * 2;
builder->data[idx++] = v1;
builder->data[idx++] = v2;
if (builder->index_len < idx) {
builder->index_len = idx;
}
}
void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3)
{
BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
BLI_assert(v1 != v2 && v2 != v3 && v3 != v1);
BLI_assert(v1 <= builder->max_allowed_index);
BLI_assert(v2 <= builder->max_allowed_index);
BLI_assert(v3 <= builder->max_allowed_index);
BLI_assert((elem + 1) * 3 <= builder->max_index_len);
uint idx = elem * 3;
builder->data[idx++] = v1;
builder->data[idx++] = v2;
builder->data[idx++] = v3;
if (builder->index_len < idx) {
builder->index_len = idx;
}
}
void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem)
{
BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
BLI_assert(elem < builder->max_index_len);
builder->data[elem++] = RESTART_INDEX;
if (builder->index_len < elem) {
builder->index_len = elem;
}
}
void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem)
{
BLI_assert(builder->prim_type == GPU_PRIM_LINES);
BLI_assert((elem + 1) * 2 <= builder->max_index_len);
uint idx = elem * 2;
builder->data[idx++] = RESTART_INDEX;
builder->data[idx++] = RESTART_INDEX;
if (builder->index_len < idx) {
builder->index_len = idx;
}
}
void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
{
BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
BLI_assert((elem + 1) * 3 <= builder->max_index_len);
uint idx = elem * 3;
builder->data[idx++] = RESTART_INDEX;
builder->data[idx++] = RESTART_INDEX;
builder->data[idx++] = RESTART_INDEX;
if (builder->index_len < idx) {
builder->index_len = idx;
}
}
GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length)
{
GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
BLI_assert(elem_src && !elem_src->is_subrange);
BLI_assert(start + length <= elem_src->index_len);
#if GPU_TRACK_INDEX_RANGE
elem->index_type = elem_src->index_type;
elem->gl_index_type = elem_src->gl_index_type;
elem->base_index = elem_src->base_index;
#endif
elem->is_subrange = true;
elem->src = elem_src;
elem->index_start = start;
elem->index_len = length;
return elem;
}
#if GPU_TRACK_INDEX_RANGE
/* Everything remains 32 bit while building to keep things simple.
* Find min/max after, then convert to smallest index type possible. */
@@ -271,6 +365,10 @@ static void indexbuf_upload_data(GPUIndexBuf *elem)
void GPU_indexbuf_use(GPUIndexBuf *elem)
{
if (elem->is_subrange) {
GPU_indexbuf_use(elem->src);
return;
}
if (elem->ibo_id == 0) {
elem->ibo_id = GPU_buf_alloc();
}
@@ -285,7 +383,7 @@ void GPU_indexbuf_discard(GPUIndexBuf *elem)
if (elem->ibo_id) {
GPU_buf_free(elem->ibo_id);
}
if (elem->data) {
if (!elem->is_subrange && elem->data) {
MEM_freeN(elem->data);
}
MEM_freeN(elem);

View File

@@ -216,6 +216,29 @@ int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name)
return -1;
}
/* Make attribute layout non-interleaved.
* Warning! This does not change data layout!
* Use direct buffer access to fill the data.
* This is for advanced usage.
*
* Deinterleaved data means all attrib data for each attrib
* is stored continuously like this :
* 000011112222
* instead of :
* 012012012012
*
* Note this is per attrib deinterleaving, NOT per component.
* */
void GPU_vertformat_deinterleave(GPUVertFormat *format)
{
/* Ideally we should change the stride and offset here. This would allow
* us to use GPU_vertbuf_attr_set / GPU_vertbuf_attr_fill. But since
* we use only 11 bits for attr->offset this limits the size of the
* buffer considerably. So instead we do the conversion when creating
* bindings in create_bindings(). */
format->deinterleaved = true;
}
uint padding(uint offset, uint alignment)
{
const uint mod = offset % alignment;
@@ -389,58 +412,3 @@ void GPU_vertformat_from_interface(GPUVertFormat *format, const GPUShaderInterfa
}
}
}
/* OpenGL ES packs in a different order as desktop GL but component conversion is the same.
* Of the code here, only struct GPUPackedNormal needs to change. */
#define SIGNED_INT_10_MAX 511
#define SIGNED_INT_10_MIN -512
static int clampi(int x, int min_allowed, int max_allowed)
{
#if TRUST_NO_ONE
assert(min_allowed <= max_allowed);
#endif
if (x < min_allowed) {
return min_allowed;
}
else if (x > max_allowed) {
return max_allowed;
}
else {
return x;
}
}
static int quantize(float x)
{
int qx = x * 511.0f;
return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX);
}
static int convert_i16(short x)
{
/* 16-bit signed --> 10-bit signed */
/* TODO: round? */
return x >> 6;
}
GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3])
{
GPUPackedNormal n = {
.x = quantize(data[0]),
.y = quantize(data[1]),
.z = quantize(data[2]),
};
return n;
}
GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3])
{
GPUPackedNormal n = {
.x = convert_i16(data[0]),
.y = convert_i16(data[1]),
.z = convert_i16(data[2]),
};
return n;
}

View File

@@ -27,6 +27,7 @@
#define __GPU_VERTEX_FORMAT_PRIVATE_H__
void VertexFormat_pack(GPUVertFormat *format);
void VertexFormat_deinterleave(GPUVertFormat *format, uint vertex_len);
uint padding(uint offset, uint alignment);
uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len);

View File

@@ -8,7 +8,7 @@ in vec2 pos;
in float stretch;
#else
in vec4 uv_adj;
in vec2 uv_angles;
in float angle;
#endif
@@ -52,6 +52,11 @@ vec3 weight_to_rgb(float weight)
#define M_PI 3.1415926535897932
vec2 angle_to_v2(float angle)
{
return vec2(cos(angle), sin(angle));
}
/* Adapted from BLI_math_vector.h */
float angle_normalized_v2v2(vec2 v1, vec2 v2)
{
@@ -69,7 +74,9 @@ void main()
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
#ifdef STRETCH_ANGLE
float uv_angle = angle_normalized_v2v2(uv_adj.xy, uv_adj.zw) / M_PI;
vec2 v1 = angle_to_v2(uv_angles.x * M_PI);
vec2 v2 = angle_to_v2(uv_angles.y * M_PI);
float uv_angle = angle_normalized_v2v2(v1, v2) / M_PI;
float stretch = 1.0 - abs(uv_angle - angle);
stretch = stretch;
stretch = 1.0 - stretch * stretch;