Sculpt Poly Loop: Move poly loop code to its own file

This commit is contained in:
Pablo Dobarro 2021-03-17 00:07:41 +01:00
parent 6408c4ebf6
commit 6835ea72f2
4 changed files with 331 additions and 3 deletions

View File

@ -74,6 +74,7 @@ set(SRC
sculpt_multiplane_scrape.c
sculpt_paint_color.c
sculpt_pose.c
sculpt_poly_loop.c
sculpt_smooth.c
sculpt_transform.c
sculpt_undo.c

View File

@ -150,8 +150,8 @@ static int sculpt_poly_loop_initial_edge_from_cursor(Object *ob) {
int closest_vert_index = mesh->mloop[initial_poly->loopstart].v;
for (int i = 0; i < initial_poly->totloop; i++) {
if (len_squared_v3v3(mvert[initial_poly->loopstart + i].co, ss->cursor_location) < len_squared_v3v3(mvert[closest_vert_index].co, ss->cursor_location)) {
closest_vert_index = initial_poly->loopstart + i;
if (len_squared_v3v3(mvert[ss->mloop[initial_poly->loopstart + i].v].co, ss->cursor_location) < len_squared_v3v3(mvert[closest_vert_index].co, ss->cursor_location)) {
closest_vert_index = ss->mloop[initial_poly->loopstart + i].v;
}
}
@ -165,7 +165,8 @@ static int sculpt_poly_loop_initial_edge_from_cursor(Object *ob) {
closest_vert_on_initial_edge_index = other_vert;
}
}
printf("INITIAL EDGE INDEX %d\n");
printf("CLOSEST VERT INDEX %d\n", closest_vert_index);
printf("INITIAL EDGE INDEX %d\n", initial_edge_index);
return initial_edge_index;
}

View File

@ -1420,6 +1420,11 @@ bool SCULPT_get_redraw_rect(struct ARegion *region,
Object *ob,
rcti *rect);
/* Poly Loops. */
BLI_bitmap * sculpt_poly_loop_from_cursor(struct Object *ob);
/* Operators. */
/* Face Set by Topology. */

View File

@ -0,0 +1,321 @@
/*
* 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) 2020 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup edsculpt
*/
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_hash.h"
#include "BLI_math.h"
#include "BLI_task.h"
#include "DNA_brush_types.h"
#include "DNA_customdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_mesh_fair.h"
#include "BKE_mesh_mapping.h"
#include "BKE_multires.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_message.h"
#include "WM_toolsystem.h"
#include "WM_types.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_view3d.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "bmesh.h"
#include <math.h>
#include <stdlib.h>
typedef enum eSculptFaceSetByTopologyMode {
SCULPT_FACE_SET_TOPOLOGY_LOOSE_PART = 0,
SCULPT_FACE_SET_TOPOLOGY_POLY_LOOP = 1,
};
static EnumPropertyItem prop_sculpt_face_set_by_topology[] = {
{
SCULPT_FACE_SET_TOPOLOGY_LOOSE_PART,
"LOOSE_PART",
0,
"Loose Part",
"",
},
{
SCULPT_FACE_SET_TOPOLOGY_POLY_LOOP,
"POLY_LOOP",
0,
"Face Loop",
"",
},
{0, NULL, 0, NULL, NULL},
};
#define SCULPT_FACE_SET_LOOP_STEP_NONE -1
static bool sculpt_poly_loop_step(SculptSession *ss, const int from_poly, const int edge, int *r_next_poly) {
if (!ss->epmap) {
return false;
}
int next_poly = SCULPT_FACE_SET_LOOP_STEP_NONE;
for (int i = 0; i < ss->epmap[edge].count; i++) {
if (ss->epmap[edge].indices[i] != from_poly) {
next_poly = ss->epmap[edge].indices[i];
}
}
if (next_poly == SCULPT_FACE_SET_LOOP_STEP_NONE) {
return false;
}
*r_next_poly = next_poly;
return true;
}
static int sculpt_poly_loop_opposite_edge_in_quad(SculptSession *ss, const int poly, const int edge) {
if (ss->mpoly[poly].totloop != 4) {
return edge;
}
int edge_index_in_poly = 0;
for (int i = 0; i < ss->mpoly[poly].totloop; i++) {
if (edge == ss->mloop[ss->mpoly[poly].loopstart + i].e) {
edge_index_in_poly = i;
break;
}
}
const int next_edge_index_in_poly = (edge_index_in_poly + 2) % 4;
return ss->mloop[ss->mpoly[poly].loopstart + next_edge_index_in_poly].e;
}
static int sculpt_poly_loop_initial_edge_from_cursor(Object *ob) {
SculptSession *ss = ob->sculpt;
Mesh *mesh = BKE_object_get_original_mesh(ob);
MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
MPoly *initial_poly = &mesh->mpoly[ss->active_face_index];
if (initial_poly->totloop != 4) {
return 0;
}
int closest_vert_index = mesh->mloop[initial_poly->loopstart].v;
for (int i = 0; i < initial_poly->totloop; i++) {
if (len_squared_v3v3(mvert[ss->mloop[initial_poly->loopstart + i].v].co, ss->cursor_location) < len_squared_v3v3(mvert[closest_vert_index].co, ss->cursor_location)) {
closest_vert_index = ss->mloop[initial_poly->loopstart + i].v;
}
}
int initial_edge_index = ss->vemap[closest_vert_index].indices[0];
int closest_vert_on_initial_edge_index = mesh->medge[initial_edge_index].v1 == closest_vert_index ? mesh->medge[initial_edge_index].v2 : mesh->medge[initial_edge_index].v1;
for (int i = 0; i < ss->vemap[closest_vert_index].count; i++) {
const int edge_index = ss->vemap[closest_vert_index].indices[i];
const int other_vert = mesh->medge[edge_index].v1 == closest_vert_index ? mesh->medge[edge_index].v2 : mesh->medge[edge_index].v1;
if (len_squared_v3v3(mvert[other_vert].co, ss->cursor_location) < len_squared_v3v3(mvert[closest_vert_on_initial_edge_index].co, ss->cursor_location)) {
initial_edge_index = edge_index;
closest_vert_on_initial_edge_index = other_vert;
}
}
printf("CLOSEST VERT INDEX %d\n", closest_vert_index);
printf("INITIAL EDGE INDEX %d\n", initial_edge_index);
return initial_edge_index;
}
static void sculpt_poly_loop_topology_data_ensure(Object *ob) {
SculptSession *ss = ob->sculpt;
Mesh *mesh = BKE_object_get_original_mesh(ob);
if (!ss->epmap) {
BKE_mesh_edge_poly_map_create(&ss->epmap,
&ss->epmap_mem,
mesh->medge,
mesh->totedge,
mesh->mpoly,
mesh->totpoly,
mesh->mloop,
mesh->totloop);
}
if (!ss->vemap) {
BKE_mesh_vert_edge_map_create(
&ss->vemap, &ss->vemap_mem, mesh->medge, mesh->totvert, mesh->totedge);
}
}
static void sculpt_poly_loop_iterate_and_fill(SculptSession *ss, const int initial_poly, const int initial_edge, BLI_bitmap *poly_loop) {
int current_poly = initial_poly;
int current_edge = initial_edge;
int next_poly = SCULPT_FACE_SET_LOOP_STEP_NONE;
int max_steps = ss->totfaces;
BLI_BITMAP_ENABLE(poly_loop, initial_poly);
while(max_steps && sculpt_poly_loop_step(ss, current_poly, current_edge, &next_poly)) {
if (ss->face_sets[next_poly] == initial_poly) {
break;
}
if (ss->face_sets[next_poly] < 0) {
break;
}
if (ss->mpoly[next_poly].totloop != 4) {
break;
}
BLI_BITMAP_ENABLE(poly_loop, next_poly);
current_edge = sculpt_poly_loop_opposite_edge_in_quad(ss, next_poly, current_edge);
current_poly = next_poly;
max_steps--;
}
}
BLI_bitmap * sculpt_poly_loop_from_cursor(Object *ob) {
SculptSession *ss = ob->sculpt;
Mesh *mesh = BKE_object_get_original_mesh(ob);
BLI_bitmap *poly_loop = BLI_BITMAP_NEW(mesh->totpoly, "poly loop");
sculpt_poly_loop_topology_data_ensure(ob);
const int initial_edge = sculpt_poly_loop_initial_edge_from_cursor(ob);
const int initial_poly = ss->active_face_index;
const int initial_edge_opposite = sculpt_poly_loop_opposite_edge_in_quad(ss, initial_poly, initial_edge);
sculpt_poly_loop_iterate_and_fill(ss, initial_poly, initial_edge, poly_loop);
sculpt_poly_loop_iterate_and_fill(ss, initial_poly, initial_edge_opposite, poly_loop);
return poly_loop;
}
static void sculpt_face_set_by_topology_poly_loop(Object *ob, const int next_face_set_id) {
SculptSession *ss = ob->sculpt;
BLI_bitmap *poly_loop = sculpt_poly_loop_from_cursor(ob);
for (int i = 0; i < ss->totfaces; i++) {
if (BLI_BITMAP_TEST(poly_loop, i)) {
ss->face_sets[i] = next_face_set_id;
}
}
MEM_freeN(poly_loop);
}
static int sculpt_face_set_by_topology_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
const int mode = RNA_enum_get(op->ptr, "mode");
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
printf("FACE SET TOPOLOGY\n");
/* Update the current active Face Set and Vertex as the operator can be used directly from the
* tool without brush cursor. */
SculptCursorGeometryInfo sgi;
const float mouse[2] = {event->mval[0], event->mval[1]};
if (!SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false, false)) {
/* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */
return OPERATOR_CANCELLED;
}
PBVHNode **nodes;
int totnode;
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
SCULPT_undo_push_begin(ob, "face set edit");
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
Mesh *mesh = BKE_object_get_original_mesh(ob);
const int next_face_set = ED_sculpt_face_sets_find_next_available_id(mesh);
printf("NEXT FACE SET %d\n", next_face_set);
switch (mode) {
case SCULPT_FACE_SET_TOPOLOGY_LOOSE_PART:
break;
case SCULPT_FACE_SET_TOPOLOGY_POLY_LOOP:
sculpt_face_set_by_topology_poly_loop(ob, next_face_set);
break;
}
/* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
SCULPT_visibility_sync_all_face_sets_to_vertices(ob);
for (int i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_update_visibility(nodes[i]);
}
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
BKE_mesh_flush_hidden_from_verts(ob->data);
}
MEM_freeN(nodes);
SCULPT_undo_push_end();
SCULPT_tag_update_overlays(C);
return OPERATOR_FINISHED;
}
void SCULPT_OT_face_set_by_topology(struct wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Face Set by Topology";
ot->idname = "SCULPT_OT_face_set_by_topology";
ot->description = "Create a new Face Set following the mesh topology";
/* Api callbacks. */
ot->invoke = sculpt_face_set_by_topology_invoke;
ot->poll = SCULPT_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_enum(
ot->srna, "mode", prop_sculpt_face_set_by_topology, SCULPT_FACE_SET_TOPOLOGY_POLY_LOOP, "Mode", "");
}