Changeset View
Standalone View
source/blender/bmesh/operators/bmo_primitive.c
| Show All 23 Lines | |||||
| * \ingroup bmesh | * \ingroup bmesh | ||||
| * | * | ||||
| * Primitive shapes. | * Primitive shapes. | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_alloca.h" | |||||
| #include "BKE_editmesh.h" | |||||
| #include "DNA_meshdata_types.h" | |||||
| #include "bmesh.h" | #include "bmesh.h" | ||||
| #include "intern/bmesh_operators_private.h" | #include "intern/bmesh_operators_private.h" | ||||
| static void BM_mesh_calc_uvs_sphere_face(BMFace *f, float rot[4][4], int cd_loop_uv_offset); | |||||
| /* ************************ primitives ******************* */ | /* ************************ primitives ******************* */ | ||||
| static const float icovert[12][3] = { | static const float icovert[12][3] = { | ||||
| {0.0f, 0.0f, -200.0f}, | {0.0f, 0.0f, -200.0f}, | ||||
| {144.72f, -105.144f, -89.443f}, | {144.72f, -105.144f, -89.443f}, | ||||
| {-55.277f, -170.128, -89.443f}, | {-55.277f, -170.128, -89.443f}, | ||||
| {-178.885f, 0.0f, -89.443f}, | {-178.885f, 0.0f, -89.443f}, | ||||
| ▲ Show 20 Lines • Show All 186 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| BMOpSlot *slot_verts_out = BMO_slot_get(op->slots_out, "verts.out"); | BMOpSlot *slot_verts_out = BMO_slot_get(op->slots_out, "verts.out"); | ||||
| const float dia = BMO_slot_float_get(op->slots_in, "size"); | const float dia = BMO_slot_float_get(op->slots_in, "size"); | ||||
| const unsigned int xtot = max_ii(2, BMO_slot_int_get(op->slots_in, "x_segments")); | const unsigned int xtot = max_ii(2, BMO_slot_int_get(op->slots_in, "x_segments")); | ||||
| const unsigned int ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments")); | const unsigned int ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments")); | ||||
| const float xtot_inv2 = 2.0f / (xtot - 1); | const float xtot_inv2 = 2.0f / (xtot - 1); | ||||
| const float ytot_inv2 = 2.0f / (ytot - 1); | const float ytot_inv2 = 2.0f / (ytot - 1); | ||||
| const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); | |||||
| BMVert **varr; | BMVert **varr; | ||||
| BMVert *vquad[4]; | BMVert *vquad[4]; | ||||
| BMFace *f; | |||||
| float mat[4][4]; | float mat[4][4]; | ||||
| float vec[3], tvec[3]; | float vec[3], tvec[3]; | ||||
| unsigned int x, y, i; | unsigned int x, y, i; | ||||
| BMO_slot_mat4_get(op->slots_in, "matrix", mat); | BMO_slot_mat4_get(op->slots_in, "matrix", mat); | ||||
| Show All 16 Lines | #define XY(_x, _y) ((_x) + ((_y) * (xtot))) | ||||
| for (y = 1; y < ytot; y++) { | for (y = 1; y < ytot; y++) { | ||||
| for (x = 1; x < xtot; x++) { | for (x = 1; x < xtot; x++) { | ||||
| vquad[0] = varr[XY(x - 1, y - 1)]; | vquad[0] = varr[XY(x - 1, y - 1)]; | ||||
| vquad[1] = varr[XY(x, y - 1)]; | vquad[1] = varr[XY(x, y - 1)]; | ||||
| vquad[2] = varr[XY(x, y)]; | vquad[2] = varr[XY(x, y)]; | ||||
| vquad[3] = varr[XY(x - 1, y)]; | vquad[3] = varr[XY(x - 1, y)]; | ||||
| BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true); | f = BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true); | ||||
| BMO_elem_flag_enable(bm, f, FACE_NEW); | |||||
| } | } | ||||
| } | } | ||||
| #undef XY | #undef XY | ||||
| if (calc_uvs) | |||||
| BM_mesh_calc_uvs_grid(bm, xtot, ytot); | |||||
| } | |||||
campbellbarton: Whats the purpose of disabling these flags? | |||||
Not Done Inline ActionsIf they stay enabled, those faces get unwrapped again next time BM_mesh_calc_uvs_grid is called on this mesh (ie. adding a second primitive, with unwrapping, to the same mesh as the first). Those flags were just enabled in this function directly above. CommanderCorianderSalamander: If they stay enabled, those faces get unwrapped again next time BM_mesh_calc_uvs_grid is called… | |||||
Not Done Inline ActionsThese flags are reset for each bmesh-operator call, you shouldn't have to initialize them. If you do - then it must be some bug in the operator flag stack. campbellbarton: These flags are reset for each bmesh-operator call, you shouldn't have to initialize them.
If… | |||||
| void BM_mesh_calc_uvs_grid(BMesh *bm, unsigned int x_segments, unsigned int y_segments) | |||||
| { | |||||
| BMFace *f; | |||||
Not Done Inline ActionsBetter make caller responsible for ensuring BMesh has UV's, This goes for all other similar functions too. campbellbarton: Better make caller responsible for ensuring BMesh has UV's, This goes for all other similar… | |||||
| BMLoop *l; | |||||
| BMIter iter, liter; | |||||
| MLoopUV *luv; | |||||
| int cd_loop_uv_offset, loopindex; | |||||
| float x, y, dx, dy; | |||||
| cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | |||||
| BLI_assert(cd_loop_uv_offset != -1); | |||||
| dx = 1.0f / (x_segments - 1); | |||||
| dy = 1.0f / (y_segments - 1); | |||||
| x = 0.0f; | |||||
| y = 0.0f; | |||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | |||||
| if (!BMO_elem_flag_test(bm, f, FACE_NEW)) | |||||
| continue; | |||||
| BMO_elem_flag_disable(bm, f, FACE_NEW); | |||||
Not Done Inline ActionsWhy disable? campbellbarton: Why disable? | |||||
| BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loopindex) { | |||||
| BMO_elem_flag_disable(bm, l->v, VERT_MARK); | |||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| switch (loopindex) { | |||||
| case 0: | |||||
| x += dx; | |||||
| break; | |||||
| case 1: | |||||
| y += dy; | |||||
| break; | |||||
| case 2: | |||||
| x -= dx; | |||||
| break; | |||||
| case 3: | |||||
| y -= dy; | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| luv->uv[0] = x; | |||||
| luv->uv[1] = y; | |||||
| } | |||||
| x += dx; | |||||
| if (x >= 1.0f) { | |||||
| x = 0.0f; | |||||
| y += dy; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) | void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) | ||||
| { | { | ||||
| const float dia = BMO_slot_float_get(op->slots_in, "diameter"); | const float dia = BMO_slot_float_get(op->slots_in, "diameter"); | ||||
| const int seg = BMO_slot_int_get(op->slots_in, "u_segments"); | const int seg = BMO_slot_int_get(op->slots_in, "u_segments"); | ||||
| const int tot = BMO_slot_int_get(op->slots_in, "v_segments"); | const int tot = BMO_slot_int_get(op->slots_in, "v_segments"); | ||||
| const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); | |||||
| BMOperator bmop, prevop; | BMOperator bmop, prevop; | ||||
| BMVert *eve, *preveve; | BMVert *eve, *preveve; | ||||
| BMEdge *e; | BMEdge *e; | ||||
| BMIter iter; | BMIter iter; | ||||
| const float axis[3] = {0, 0, 1}; | const float axis[3] = {0, 0, 1}; | ||||
| float vec[3], mat[4][4], cmat[3][3]; | float vec[3], mat[4][4], cmat[3][3]; | ||||
| float phi, phid; | float phi, phid; | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | if (a) | ||||
| mul_v3_m3v3(vec2, cmat, vec); | mul_v3_m3v3(vec2, cmat, vec); | ||||
| len2 = len_v3v3(vec, vec2); | len2 = len_v3v3(vec, vec2); | ||||
| /* use shortest segment length divided by 3 as merge threshold */ | /* use shortest segment length divided by 3 as merge threshold */ | ||||
| BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, min_ff(len, len2) / 3.0f); | BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, min_ff(len, len2) / 3.0f); | ||||
| } | } | ||||
| if (calc_uvs) | |||||
| BM_mesh_calc_uvs_sphere(bm); | |||||
| /* and now do imat */ | /* and now do imat */ | ||||
| BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { | BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { | ||||
| if (BMO_elem_flag_test(bm, eve, VERT_MARK)) { | if (BMO_elem_flag_test(bm, eve, VERT_MARK)) { | ||||
| mul_m4_v3(mat, eve->co); | mul_m4_v3(mat, eve->co); | ||||
| } | } | ||||
| } | } | ||||
| BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); | BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); | ||||
| } | } | ||||
| void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) | void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) | ||||
| { | { | ||||
| const float dia = BMO_slot_float_get(op->slots_in, "diameter"); | const float dia = BMO_slot_float_get(op->slots_in, "diameter"); | ||||
| const float dia_div = dia / 200.0f; | const float dia_div = dia / 200.0f; | ||||
| const int subdiv = BMO_slot_int_get(op->slots_in, "subdivisions"); | const int subdiv = BMO_slot_int_get(op->slots_in, "subdivisions"); | ||||
| const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); | |||||
| BMVert *eva[12]; | BMVert *eva[12]; | ||||
| BMVert *v; | BMVert *v; | ||||
| BMIter liter; | BMIter liter; | ||||
| BMIter viter; | BMIter viter; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| float vec[3], mat[4][4] /* , phi, phid */; | float vec[3], mat[4][4] /* , phi, phid */; | ||||
| int a; | int a; | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | BMO_op_initf(bm, &bmop, op->flag, | ||||
| true, true); | true, true); | ||||
| BMO_op_exec(bm, &bmop); | BMO_op_exec(bm, &bmop); | ||||
| BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_VERT, VERT_MARK); | BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_VERT, VERT_MARK); | ||||
| BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_EDGE, EDGE_MARK); | BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_EDGE, EDGE_MARK); | ||||
| BMO_op_finish(bm, &bmop); | BMO_op_finish(bm, &bmop); | ||||
| } | } | ||||
| if (calc_uvs) | |||||
| BM_mesh_calc_uvs_sphere(bm); | |||||
| /* must transform after because of sphere subdivision */ | /* must transform after because of sphere subdivision */ | ||||
| BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { | BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { | ||||
| if (BMO_elem_flag_test(bm, v, VERT_MARK)) { | if (BMO_elem_flag_test(bm, v, VERT_MARK)) { | ||||
| mul_m4_v3(mat, v->co); | mul_m4_v3(mat, v->co); | ||||
| } | } | ||||
| } | } | ||||
| BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); | BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); | ||||
| } | } | ||||
| /* since we need to call alloca best to split this loop body into its own function */ | |||||
| void BM_mesh_calc_uvs_sphere_face(BMFace *f, float rot[4][4], int cd_loop_uv_offset) { | |||||
Not Done Inline Actionsalloca wont be freed until the function exits. you have to be very careful calling alloca in a loop, and in this case it can easily run out of stack memory and crash. In this case you could move the body of the for loop into a static function. campbellbarton: `alloca` wont be freed until the function exits. you have to be very careful calling alloca in… | |||||
mont29AuthorUnsubmitted Not Done Inline Actionsshouldn’t this func be static? If static, please also rename it to bm_mesh_calc_uvs_sphere_face mont29: shouldn’t this func be static?
If static, please also rename it to… | |||||
CommanderCorianderSalamanderUnsubmitted Not Done Inline ActionsIt's declared static at the top of the file ;) CommanderCorianderSalamander: It's declared static at the top of the file ;) | |||||
| float **uvs = BLI_array_alloca(uvs, f->len); | |||||
mont29AuthorUnsubmitted Not Done Inline ActionsWith UVSphere or IcoSphere, len will never be > 4, no need to use alloca in this case imho, just simply use a float (*)[4] table (with a BLI_assert on f->len)? Or do you want this func to be usable with any kind of sphere-like geometry? mont29: With UVSphere or IcoSphere, len will never be > 4, no need to use alloca in this case imho… | |||||
| BMLoop *l; | |||||
| BMIter iter; | |||||
| MLoopUV *luv; | |||||
| float v[3] = {0}; | |||||
mont29AuthorUnsubmitted Not Done Inline Actionsbetter to use zero_v3(v) later. But do this vec need to be initialized at all? mont29: better to use zero_v3(v) later. But do this vec need to be initialized at all? | |||||
| float dx; | |||||
| int mi, i; | |||||
| BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) { | |||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| copy_v3_v3(v, l->v->co); | |||||
| mul_m4_v3(rot, v); | |||||
| map_to_sphere(&luv->uv[0], &luv->uv[1], v[0], v[1], v[2]); | |||||
| uvs[i] = luv->uv; | |||||
| } | |||||
| mi = 0; /* fix awkwardly-wrapping UVs */ | |||||
| for (i = 1; i < f->len; ++i) | |||||
mont29AuthorUnsubmitted Not Done Inline ActionsConventions are to use post-increment in our C code (same for other loops below). mont29: Conventions are to use post-increment in our C code (same for other loops below). | |||||
| if (uvs[i][0] > uvs[mi][0]) | |||||
| mi = i; | |||||
| for (i = 0; i < f->len; ++i) { | |||||
| if (i != mi) { | |||||
| dx = uvs[mi][0] - uvs[i][0]; | |||||
| if (dx > 0.5f) uvs[i][0] += 1.0f; | |||||
mont29AuthorUnsubmitted Not Done Inline Actionseeeh, a one-line if() I missed! mont29: eeeh, a one-line if() I missed! | |||||
| } | |||||
| } | |||||
| } | |||||
| void BM_mesh_calc_uvs_sphere(BMesh *bm) | |||||
| { | |||||
Not Done Inline ActionsThis is around 4440 degrees, This could be 2.1 since the value is in radians. campbellbarton: This is around `4440` degrees, This could be `2.1` since the value is in radians. | |||||
| BMFace *f; | |||||
| BMIter iter; | |||||
| int cd_loop_uv_offset; | |||||
| float v[3] = { 0 }; | |||||
| float rot[4][4]; | |||||
| float axis[3] = {0.806f, 0.329f, 0.491f}; /* magic numbers - seem to be best for both ico and uv sphere projections */ | |||||
| float angle = 2.1f; /* more magic! */ | |||||
| float size[3] = { 1, 1, 1 }; | |||||
mont29AuthorUnsubmitted Not Done Inline Actionsanother one I missed, no spaces between brackets and numbers, and please use full float format (1.0f). mont29: another one I missed, no spaces between brackets and numbers, and please use full float format… | |||||
| cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | |||||
| BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */ | |||||
| loc_axisangle_size_to_mat4(rot, v, axis, angle, size); | |||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | |||||
| BM_mesh_calc_uvs_sphere_face(f, rot, cd_loop_uv_offset); | |||||
| } | |||||
| } | |||||
| void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) | void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) | ||||
| { | { | ||||
Not Done Inline ActionsThis is applying to all faces, which will overwrite existing UV's if you add a new sphere while in edit-mode. campbellbarton: This is applying to **all faces**, which will overwrite existing UV's if you add a new sphere… | |||||
Not Done Inline ActionsYes - this is actually the problem I was trying to solve in the other primitives by enabling/disabling FACE_NEW. Forgot to deal with it here =( CommanderCorianderSalamander: Yes - this is actually the problem I was trying to solve in the other primitives by… | |||||
| BMVert *eve; | BMVert *eve; | ||||
| BMVert **tv = MEM_mallocN(sizeof(*tv) * monkeynv * 2, "tv"); | BMVert **tv = MEM_mallocN(sizeof(*tv) * monkeynv * 2, "tv"); | ||||
| float mat[4][4]; | float mat[4][4]; | ||||
| int i; | int i; | ||||
| BMO_slot_mat4_get(op->slots_in, "matrix", mat); | BMO_slot_mat4_get(op->slots_in, "matrix", mat); | ||||
| for (i = 0; i < monkeynv; i++) { | for (i = 0; i < monkeynv; i++) { | ||||
| Show All 39 Lines | |||||
| void bmo_create_circle_exec(BMesh *bm, BMOperator *op) | void bmo_create_circle_exec(BMesh *bm, BMOperator *op) | ||||
| { | { | ||||
| const float dia = BMO_slot_float_get(op->slots_in, "diameter"); | const float dia = BMO_slot_float_get(op->slots_in, "diameter"); | ||||
| const int segs = BMO_slot_int_get(op->slots_in, "segments"); | const int segs = BMO_slot_int_get(op->slots_in, "segments"); | ||||
| const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); | const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); | ||||
| const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); | const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); | ||||
| const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); | |||||
| BMVert *v1, *lastv1 = NULL, *cent1, *firstv1 = NULL; | BMVert *v1, *lastv1 = NULL, *cent1, *firstv1 = NULL; | ||||
| float vec[3], mat[4][4], phi, phid; | float vec[3], mat[4][4], phi, phid; | ||||
| int a; | int a; | ||||
| if (!segs) | if (!segs) | ||||
| return; | return; | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | void bmo_create_circle_exec(BMesh *bm, BMOperator *op) | ||||
| BM_edge_create(bm, firstv1, lastv1, NULL, 0); | BM_edge_create(bm, firstv1, lastv1, NULL, 0); | ||||
| if (cap_ends) { | if (cap_ends) { | ||||
| BMFace *f; | BMFace *f; | ||||
| f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, false); | f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, false); | ||||
| BMO_elem_flag_enable(bm, f, FACE_NEW); | BMO_elem_flag_enable(bm, f, FACE_NEW); | ||||
| if (calc_uvs) | |||||
| BM_mesh_calc_uvs_circle(bm, mat, dia); | |||||
| } | } | ||||
Not Done Inline ActionsCode style: use 0.5f, not .5 kevindietrich: Code style: use 0.5f, not .5 | |||||
| if (!cap_tris) { | if (!cap_tris) { | ||||
| BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); | BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); | ||||
| } | } | ||||
| BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); | BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); | ||||
| } | } | ||||
| void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], float radius) { | |||||
| BMFace *f; | |||||
| BMLoop *l; | |||||
Not Done Inline Actionscampbellbarton: style: http://wiki.blender.org/index.php/Dev:Doc/Code_Style#Braces | |||||
| BMIter iter, liter; | |||||
| MLoopUV *luv; | |||||
| int cd_loop_uv_offset; | |||||
| int loopindex; | |||||
| float v_transform[3], inv_mat[4][4]; | |||||
| const float scale = 0.5f / radius; | |||||
| const float center = 0.5f; | |||||
| cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | |||||
| BLI_assert(cd_loop_uv_offset != -1); /* caller must ensure we have UVs already */ | |||||
| invert_m4_m4(inv_mat, mat); | |||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | |||||
| if (!BMO_elem_flag_test(bm, f, FACE_NEW)) | |||||
| continue; | |||||
| BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loopindex) { | |||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| copy_v3_v3(v_transform, l->v->co); | |||||
| /* transform back into the unit circle flat on the Z-axis */ | |||||
| mul_m4_v3(inv_mat, v_transform); | |||||
| /* then just take those coords for UVs */ | |||||
| luv->uv[0] = center + scale * v_transform[0]; | |||||
| luv->uv[1] = center + scale * v_transform[1]; | |||||
| } | |||||
| } | |||||
| } | |||||
| void bmo_create_cone_exec(BMesh *bm, BMOperator *op) | void bmo_create_cone_exec(BMesh *bm, BMOperator *op) | ||||
| { | { | ||||
| BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2; | BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2; | ||||
| BMFace *f; | |||||
| float vec[3], mat[4][4], phi, phid; | float vec[3], mat[4][4], phi, phid; | ||||
| float dia1 = BMO_slot_float_get(op->slots_in, "diameter1"); | float dia1 = BMO_slot_float_get(op->slots_in, "diameter1"); | ||||
| float dia2 = BMO_slot_float_get(op->slots_in, "diameter2"); | float dia2 = BMO_slot_float_get(op->slots_in, "diameter2"); | ||||
| float depth = BMO_slot_float_get(op->slots_in, "depth"); | float depth = BMO_slot_float_get(op->slots_in, "depth"); | ||||
| int segs = BMO_slot_int_get(op->slots_in, "segments"); | int segs = BMO_slot_int_get(op->slots_in, "segments"); | ||||
| const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); | const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); | ||||
| const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); | const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); | ||||
| const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); | |||||
| int a; | int a; | ||||
| if (!segs) | if (!segs) | ||||
| return; | return; | ||||
| BMO_slot_mat4_get(op->slots_in, "matrix", mat); | BMO_slot_mat4_get(op->slots_in, "matrix", mat); | ||||
| phid = 2.0f * (float)M_PI / segs; | phid = 2.0f * (float)M_PI / segs; | ||||
| Show All 30 Lines | for (a = 0; a < segs; a++, phi += phid) { | ||||
| mul_m4_v3(mat, vec); | mul_m4_v3(mat, vec); | ||||
| v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); | v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); | ||||
| BMO_elem_flag_enable(bm, v1, VERT_MARK); | BMO_elem_flag_enable(bm, v1, VERT_MARK); | ||||
| BMO_elem_flag_enable(bm, v2, VERT_MARK); | BMO_elem_flag_enable(bm, v2, VERT_MARK); | ||||
| if (a) { | if (a) { | ||||
| if (cap_ends) { | if (cap_ends) { | ||||
| BMFace *f; | |||||
| f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, false); | f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, false); | ||||
| BMO_elem_flag_enable(bm, f, FACE_NEW); | if (calc_uvs) | ||||
| BM_face_normal_update(f); | |||||
| BMO_elem_flag_enable(bm, f, FACE_NEW | FACE_MARK); | |||||
| f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, false); | f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, false); | ||||
| BMO_elem_flag_enable(bm, f, FACE_NEW); | if (calc_uvs) | ||||
| BM_face_normal_update(f); | |||||
| BMO_elem_flag_enable(bm, f, FACE_NEW | FACE_MARK); | |||||
| } | } | ||||
| BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, false); | |||||
Not Done Inline ActionsWith all this effort to calculate the normals, probably better just to call. BM_face_calc_normal campbellbarton: With all this effort to calculate the normals, probably better just to call. | |||||
| f = BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, false); | |||||
| if (calc_uvs) | |||||
| BM_face_normal_update(f); | |||||
| BMO_elem_flag_enable(bm, f, FACE_MARK); | |||||
| } | } | ||||
| else { | else { | ||||
| firstv1 = v1; | firstv1 = v1; | ||||
| firstv2 = v2; | firstv2 = v2; | ||||
| } | } | ||||
| lastv1 = v1; | lastv1 = v1; | ||||
| lastv2 = v2; | lastv2 = v2; | ||||
| } | } | ||||
| if (!a) | if (!a) | ||||
| return; | return; | ||||
| if (cap_ends) { | f = BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, false); | ||||
| BMFace *f; | if (calc_uvs) | ||||
| BM_face_normal_update(f); | |||||
| BMO_elem_flag_enable(bm, f, FACE_MARK); | |||||
| if (cap_ends) { | |||||
| f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, false); | f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, false); | ||||
| BMO_elem_flag_enable(bm, f, FACE_NEW); | if (calc_uvs) | ||||
| BM_face_normal_update(f); | |||||
| BMO_elem_flag_enable(bm, f, FACE_NEW | FACE_MARK); | |||||
| f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, false); | f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, false); | ||||
| BMO_elem_flag_enable(bm, f, FACE_NEW); | if (calc_uvs) | ||||
| BM_face_normal_update(f); | |||||
| BMO_elem_flag_enable(bm, f, FACE_NEW | FACE_MARK); | |||||
| } | } | ||||
| if (calc_uvs) | |||||
| BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs); | |||||
| if (!cap_tris) { | if (!cap_tris) { | ||||
| BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); | BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); | ||||
| } | } | ||||
| BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, false); | |||||
mont29AuthorUnsubmitted Not Done Inline ActionsWhy is this removed??? mont29: Why is this removed??? | |||||
CommanderCorianderSalamanderUnsubmitted Not Done Inline ActionsJust moved up a few lines so all the faces were made before the dissolve_faces call - it made calc_uvs simpler if it could assume it was capped with triangles (I think! it's been a while) CommanderCorianderSalamander: Just moved up a few lines so all the faces were made before the dissolve_faces call - it made… | |||||
| BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001); | BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001); | ||||
| BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); | BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); | ||||
| } | } | ||||
| void BM_mesh_calc_uvs_cone(BMesh *bm, float mat[4][4], float radius_top, float radius_bottom, int segments) | |||||
| { | |||||
| BMFace *f; | |||||
| BMLoop *l; | |||||
| BMIter iter, liter; | |||||
| MLoopUV *luv; | |||||
| int cd_loop_uv_offset; | |||||
| float dx, dy, width; | |||||
| float v_transform[3], inv_mat[4][4]; | |||||
| float local_up[3] = {0.0f, 0.0f, 1.0f}; | |||||
| int i; | |||||
| const float radius = 0.24f; | |||||
| const float scale_top = (radius_top) ? (radius / radius_top) : (radius / radius_bottom); /* if we don't have a top or bottom */ | |||||
| const float scale_bottom = (radius_bottom) ? (radius / radius_bottom) : (radius / radius_top); /* then use the other scale */ | |||||
| const float center = 0.25f; | |||||
| const float center2 = 0.75f; | |||||
| const float height = 0.5f; | |||||
| cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | |||||
| copy_m4_m4(inv_mat, mat); | |||||
| for (i = 0; i < 3; ++i) /* to transform the upvector, we want to ignore translation */ | |||||
| inv_mat[3][i] = 0; | |||||
mont29AuthorUnsubmitted Not Done Inline ActionsThis can rather simply be zero_v3(inv_mat[3]) mont29: This can rather simply be `zero_v3(inv_mat[3])` | |||||
| mul_m4_v3(inv_mat, local_up); /* transform the upvector like we did the cone itself */ | |||||
| invert_m4_m4(inv_mat, mat); /* and now save the inverse of the whole transform for operation on vertices */ | |||||
| BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for ensuring the mesh has UVs */ | |||||
| dx = 0.0f; | |||||
| dy = 0.5f; | |||||
| width = 1.0f / segments; | |||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | |||||
| if (!BMO_elem_flag_test(bm, f, FACE_MARK)) | |||||
| continue; | |||||
| BMO_elem_flag_disable(bm, f, FACE_MARK); | |||||
| if (f->len == 4 && radius_top && radius_bottom) { | |||||
| /* side face - so unwrap it in a rectangle */ | |||||
| BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, i) { | |||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| switch (i) { | |||||
| case 0: | |||||
| dx += width; | |||||
| break; | |||||
| case 1: | |||||
| dy += height; | |||||
| break; | |||||
| case 2: | |||||
Not Done Inline Actionscould just pass this in. campbellbarton: could just pass this in. | |||||
Not Done Inline ActionsWhy disable? campbellbarton: Why disable? | |||||
| dx -= width; | |||||
| break; | |||||
Not Done Inline Actions0.24f could be made a const float and assigned a value. Same for other values re-used many times in this patch. campbellbarton: `0.24f` could be made a `const float` and assigned a value. Same for other values re-used many… | |||||
| case 3: | |||||
| dy -= height; | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| luv->uv[0] = dx; | |||||
| luv->uv[1] = dy; | |||||
| } | |||||
| dx += width; | |||||
| } | |||||
| else { | |||||
| /* top or bottom face - so unwrap it by transforming back to a circle and using the X/Y coords */ | |||||
| BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | |||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| copy_v3_v3(v_transform, l->v->co); | |||||
| mul_m4_v3(inv_mat, v_transform); | |||||
| if (dot_v3v3(f->no, local_up) > 0) { /* if this is a top face of the cone */ | |||||
| luv->uv[0] = center + v_transform[0] * scale_top; | |||||
| luv->uv[1] = center + v_transform[1] * scale_top; | |||||
| } | |||||
| else { | |||||
| luv->uv[0] = center2 + v_transform[0] * scale_bottom; | |||||
| luv->uv[1] = center + v_transform[1] * scale_bottom; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| void bmo_create_cube_exec(BMesh *bm, BMOperator *op) | void bmo_create_cube_exec(BMesh *bm, BMOperator *op) | ||||
| { | { | ||||
| BMVert *v1, *v2, *v3, *v4, *v5, *v6, *v7, *v8; | BMVert *v1, *v2, *v3, *v4, *v5, *v6, *v7, *v8; | ||||
| float vec[3], mat[4][4], off = BMO_slot_float_get(op->slots_in, "size") / 2.0f; | float vec[3], mat[4][4], off = BMO_slot_float_get(op->slots_in, "size") / 2.0f; | ||||
| const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); | |||||
| BMO_slot_mat4_get(op->slots_in, "matrix", mat); | BMO_slot_mat4_get(op->slots_in, "matrix", mat); | ||||
Not Done Inline Actionscan use the dot product here. campbellbarton: can use the dot product here. | |||||
| if (!off) off = 0.5f; | if (!off) off = 0.5f; | ||||
| vec[0] = -off; | vec[0] = -off; | ||||
| vec[1] = -off; | vec[1] = -off; | ||||
| vec[2] = -off; | vec[2] = -off; | ||||
| mul_m4_v3(mat, vec); | mul_m4_v3(mat, vec); | ||||
| v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); | v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); | ||||
| ▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | void bmo_create_cube_exec(BMesh *bm, BMOperator *op) | ||||
| BM_face_create_quad_tri(bm, v7, v8, v4, v3, NULL, false); | BM_face_create_quad_tri(bm, v7, v8, v4, v3, NULL, false); | ||||
| BM_face_create_quad_tri(bm, v8, v5, v1, v4, NULL, false); | BM_face_create_quad_tri(bm, v8, v5, v1, v4, NULL, false); | ||||
| /* top/bottom */ | /* top/bottom */ | ||||
| BM_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, false); | BM_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, false); | ||||
| BM_face_create_quad_tri(bm, v8, v7, v6, v5, NULL, false); | BM_face_create_quad_tri(bm, v8, v7, v6, v5, NULL, false); | ||||
| BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); | BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); | ||||
| if (calc_uvs) | |||||
| BM_mesh_calc_uvs_cube(bm); | |||||
| } | |||||
| void BM_mesh_calc_uvs_cube(BMesh *bm) | |||||
| { | |||||
| int cd_loop_uv_offset, faceindex, loopindex; | |||||
| float dx, dy; | |||||
| BMFace *f; | |||||
| BMLoop *l; | |||||
| BMIter iter, liter; | |||||
| MLoopUV *luv; | |||||
| bool flagged; | |||||
| const float width = 0.25f; | |||||
| cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | |||||
| BLI_assert(cd_loop_uv_offset != -1); /* the caller can ensure that we have UVs */ | |||||
| dx = 0.375f; | |||||
| dy = 0.0f; | |||||
| BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, faceindex) { | |||||
| flagged = true; | |||||
| BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loopindex) { | |||||
| if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) { | |||||
| flagged = false; | |||||
| BMO_elem_flag_disable(bm, l->v, VERT_MARK); | |||||
mont29AuthorUnsubmitted Not Done Inline ActionsThat flag is already disabled here. ;) mont29: That flag is already disabled here. ;) | |||||
| continue; | |||||
| } | |||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| luv->uv[0] = dx; | |||||
| luv->uv[1] = dy; | |||||
| switch (loopindex) { | |||||
| case 0: | |||||
| dx += width; | |||||
| break; | |||||
| case 1: | |||||
| dy += width; | |||||
| break; | |||||
| case 2: | |||||
| dx -= width; | |||||
| break; | |||||
| case 3: | |||||
| dy -= width; | |||||
| break; | |||||
| default: | |||||
| dx = dy = 0.0f; | |||||
mont29AuthorUnsubmitted Not Done Inline ActionsNo need to set dx/dy in the default case imho, this one will never be reached anyway. mont29: No need to set dx/dy in the default case imho, this one will never be reached anyway. | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (flagged) { | |||||
| if (dy >= 0.75f && dx > 0.125f) { | |||||
| dx = 0.125f; | |||||
| dy = 0.5f; | |||||
| } | |||||
| else if (dx <= 0.125f) { | |||||
| dx = 0.625f; | |||||
| dy = 0.5f; | |||||
| } | |||||
| else { | |||||
| dy += 0.25f; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
Whats the purpose of disabling these flags?