Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h8
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c469
-rw-r--r--source/blender/editors/include/ED_object.h1
-rw-r--r--source/blender/editors/mesh/editmesh_add.c82
-rw-r--r--source/blender/editors/object/object_add.c5
6 files changed, 545 insertions, 26 deletions
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index d92bdc6ea69..72a8dac534a 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1567,6 +1567,7 @@ static BMOpDefine bmo_create_grid_def = {
{"y_segments", BMO_OP_SLOT_INT}, /* number of y segments */
{"size", BMO_OP_SLOT_FLT}, /* size of the grid */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1590,6 +1591,7 @@ static BMOpDefine bmo_create_uvsphere_def = {
{"v_segments", BMO_OP_SLOT_INT}, /* number of v segment */
{"diameter", BMO_OP_SLOT_FLT}, /* diameter */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1612,6 +1614,7 @@ static BMOpDefine bmo_create_icosphere_def = {
{{"subdivisions", BMO_OP_SLOT_INT}, /* how many times to recursively subdivide the sphere */
{"diameter", BMO_OP_SLOT_FLT}, /* diameter */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1658,6 +1661,7 @@ static BMOpDefine bmo_create_cone_def = {
{"diameter2", BMO_OP_SLOT_FLT}, /* diameter of the opposite */
{"depth", BMO_OP_SLOT_FLT}, /* distance between ends */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1680,6 +1684,7 @@ static BMOpDefine bmo_create_circle_def = {
{"segments", BMO_OP_SLOT_INT},
{"diameter", BMO_OP_SLOT_FLT}, /* diameter of one end */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1701,6 +1706,7 @@ static BMOpDefine bmo_create_cube_def = {
/* slots_in */
{{"size", BMO_OP_SLOT_FLT}, /* size of the cube */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index d9961e589da..0a4fb1d56a4 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -141,6 +141,14 @@ void BM_mesh_esubdivide(
const short use_only_quads,
const int seed);
+void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag);
+void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag);
+void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag);
+void BM_mesh_calc_uvs_cone(
+ BMesh *bm, float mat[4][4],
+ const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag);
+void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag);
+
#include "intern/bmesh_operator_api_inline.h"
#endif /* __BMESH_OPERATORS_H__ */
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index 2108a2c0589..944f26eb131 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -30,6 +30,10 @@
#include "BLI_math.h"
+#include "BKE_customdata.h"
+
+#include "DNA_meshdata_types.h"
+
#include "bmesh.h"
#include "intern/bmesh_operators_private.h"
@@ -235,6 +239,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
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 ytot_inv2 = 2.0f / (ytot - 1);
+ const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMVert **varr;
BMVert *vquad[4];
@@ -265,17 +270,86 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
for (y = 1; y < ytot; y++) {
for (x = 1; x < xtot; x++) {
+ BMFace *f;
+
vquad[0] = varr[XY(x - 1, y - 1)];
vquad[1] = varr[XY(x, y - 1)];
vquad[2] = varr[XY(x, 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);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
}
}
#undef XY
+ if (calc_uvs) {
+ BM_mesh_calc_uvs_grid(bm, xtot, ytot, FACE_MARK);
+ }
+}
+
+/**
+ * Fills first available UVmap with grid-like UVs for all faces OpFlag-ged by given flag.
+ *
+ * \param bm The BMesh to operate on
+ * \param x_segments The x-resolution of the grid
+ * \param y_segments The y-resolution of the grid
+ * \param oflag The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag)
+{
+ BMFace *f;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ const float dx = 1.0f / (float)(x_segments - 1);
+ const float dy = 1.0f / (float)(y_segments - 1);
+ float x = 0.0f;
+ float y = 0.0f;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ int loop_index;
+
+ BLI_assert(cd_loop_uv_offset != -1);
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, f, oflag))
+ continue;
+
+ BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ switch (loop_index) {
+ 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)
@@ -283,6 +357,7 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
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 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;
BMVert *eve, *preveve;
@@ -358,6 +433,31 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, min_ff(len, len2) / 3.0f);
}
+ if (calc_uvs) {
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+
+ /* We cannot tag faces for UVs computing above, so we have to do it now, based on all its vertices
+ * being tagged. */
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ bool valid = true;
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (valid) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
+ }
+
+ BM_mesh_calc_uvs_sphere(bm, FACE_MARK);
+ }
+
/* and now do imat */
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (BMO_elem_flag_test(bm, eve, VERT_MARK)) {
@@ -373,6 +473,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
const float dia = BMO_slot_float_get(op->slots_in, "diameter");
const float dia_div = dia / 200.0f;
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 *v;
@@ -431,6 +532,30 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
BMO_op_finish(bm, &bmop);
}
+ if (calc_uvs) {
+ BMFace *f;
+ BMIter fiter;
+
+ /* We cannot tag faces for UVs computing above, so we have to do it now, based on all its vertices
+ * being tagged. */
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ bool valid = true;
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (valid) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
+ }
+
+ BM_mesh_calc_uvs_sphere(bm, FACE_MARK);
+ }
+
/* must transform after because of sphere subdivision */
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
@@ -441,6 +566,75 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
+static void bm_mesh_calc_uvs_sphere_face(BMFace *f, float mat_rot[3][3], const int cd_loop_uv_offset)
+{
+ float *uvs[4];
+ BMLoop *l;
+ BMIter iter;
+ float dx;
+ int loop_index, loop_index_max_x;
+
+ BLI_assert(f->len <= 4);
+
+ BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ float vco[3];
+
+ mul_v3_m3v3(vco, mat_rot, l->v->co);
+ map_to_sphere(&luv->uv[0], &luv->uv[1], vco[0], vco[1], vco[2]);
+
+ uvs[loop_index] = luv->uv;
+ }
+
+ /* Fix awkwardly-wrapping UVs */
+ loop_index_max_x = 0;
+ for (loop_index = 1; loop_index < f->len; loop_index++) {
+ if (uvs[loop_index][0] > uvs[loop_index_max_x][0]) {
+ loop_index_max_x = loop_index;
+ }
+ }
+
+ for (loop_index = 0; loop_index < f->len; loop_index++) {
+ if (loop_index != loop_index_max_x) {
+ dx = uvs[loop_index_max_x][0] - uvs[loop_index][0];
+ if (dx > 0.5f) {
+ uvs[loop_index][0] += 1.0f;
+ }
+ }
+ }
+}
+
+/**
+ * Fills first available UVmap with spherical projected UVs for all faces OpFlag-ged by given flag.
+ *
+ * \param bm The BMesh to operate on
+ * \param oflag The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag)
+{
+ BMFace *f;
+ BMIter iter;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ /* We apply a 'magic' rotationto vcos before mapping them to sphere,
+ * those values seem to give best results for both ico and uv sphere projections. */
+ float mat_rot[3][3];
+ const float axis[3] = {0.806f, 0.329f, 0.491f};
+ const float angle = DEG2RADF(120.0f);
+
+ axis_angle_to_mat3(mat_rot, axis, angle);
+
+ BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, f, oflag))
+ continue;
+
+ bm_mesh_calc_uvs_sphere_face(f, mat_rot, cd_loop_uv_offset);
+ }
+}
+
void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
{
BMVert *eve;
@@ -498,6 +692,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
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_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;
float vec[3], mat[4][4], phi, phid;
@@ -555,6 +750,10 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, f, FACE_NEW);
+
+ if (calc_uvs) {
+ BM_mesh_calc_uvs_circle(bm, mat, dia, FACE_NEW);
+ }
}
if (!cap_tris) {
@@ -564,9 +763,54 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
+/**
+ * Fills first available UVmap with 2D projected UVs for all faces OpFlag-ged by given flag.
+ *
+ * \param bm The BMesh to operate on.
+ * \param mat The transform matrix applied to the created circle.
+ * \param radius The size of the circle.
+ * \param oflag The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag)
+{
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ const float uv_scale = 0.5f / radius;
+ const float uv_center = 0.5f;
+
+ float inv_mat[4][4];
+
+ BLI_assert(cd_loop_uv_offset != -1); /* caller must ensure we have UVs already */
+
+ invert_m4_m4(inv_mat, mat);
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, f, oflag))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ float uv_vco[3];
+ copy_v3_v3(uv_vco, l->v->co);
+ /* transform back into the unit circle flat on the Z-axis */
+ mul_m4_v3(inv_mat, uv_vco);
+
+ /* then just take those coords for UVs */
+ luv->uv[0] = uv_center + uv_scale * uv_vco[0];
+ luv->uv[1] = uv_center + uv_scale * uv_vco[1];
+ }
+ }
+}
+
void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
{
BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2;
+ BMFace *f;
float vec[3], mat[4][4], phi, phid;
float dia1 = BMO_slot_float_get(op->slots_in, "diameter1");
float dia2 = BMO_slot_float_get(op->slots_in, "diameter2");
@@ -574,6 +818,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
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_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;
if (!segs)
@@ -620,14 +865,23 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
if (a) {
if (cap_ends) {
- BMFace *f;
-
f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
BMO_elem_flag_enable(bm, f, FACE_NEW);
+
f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
BMO_elem_flag_enable(bm, f, FACE_NEW);
}
- BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP);
+
+ f = BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
}
else {
firstv1 = v1;
@@ -642,29 +896,149 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
return;
if (cap_ends) {
- BMFace *f;
-
f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
BMO_elem_flag_enable(bm, f, FACE_NEW);
+
f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
BMO_elem_flag_enable(bm, f, FACE_NEW);
}
-
+
+ f = BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
+
+ if (calc_uvs) {
+ BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK);
+ }
+
if (!cap_tris) {
BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW);
}
- BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP);
-
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);
}
+/**
+ * Fills first available UVmap with cylinder/cone-like UVs for all faces OpFlag-ged by given flag.
+ *
+ * \param bm The BMesh to operate on.
+ * \param mat The transform matrix applied to the created cone/cylinder.
+ * \param radius_top The size of the top end of the cone/cylynder.
+ * \param radius_bottom The size of the bottom end of the cone/cylynder.
+ * \param segments The number of subdivisions in the sides of the cone/cylinder.
+ * \param cap_ends Whether the ends of the cone/cylinder are filled or not.
+ * \param oflag The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_cone(
+ BMesh *bm, float mat[4][4],
+ const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag)
+{
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ const float uv_width = 1.0f / (float)segments;
+ const float uv_height = cap_ends ? 0.5f : 1.0f;
+
+ /* Note that all this allows us to handle all cases (real cone, truncated cone, with or without ends capped)
+ * with a single common code. */
+ const float uv_center_y = cap_ends ? 0.25f : 0.5f;
+ const float uv_center_x_top = cap_ends ? 0.25f : 0.5f;
+ const float uv_center_x_bottom = cap_ends ? 0.75f : 0.5f;
+ const float uv_radius = cap_ends ? 0.24f : 0.5f;
+
+ /* Using the opposite's end uv_scale as fallback allows us to handle 'real cone' case. */
+ const float uv_scale_top = (radius_top != 0.0f) ? (uv_radius / radius_top) :
+ ((radius_bottom != 0.0f) ? (uv_radius / radius_bottom) : uv_radius);
+ const float uv_scale_bottom = (radius_bottom != 0.0f) ? (uv_radius / radius_bottom) :
+ uv_scale_top;
+
+ float local_up[3] = {0.0f, 0.0f, 1.0f};
+
+ float x, y;
+ float inv_mat[4][4];
+ int loop_index;
+
+ mul_mat3_m4_v3(mat, local_up); /* transform the upvector like we did the cone itself, without location. */
+ normalize_v3(local_up); /* remove global scaling... */
+
+ invert_m4_m4(inv_mat, mat);
+
+ BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for ensuring the mesh has UVs */
+
+ x = 0.0f;
+ y = 1.0f - uv_height;
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, f, oflag))
+ continue;
+
+ 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, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ switch (loop_index) {
+ case 0:
+ x += uv_width;
+ break;
+ case 1:
+ y += uv_height;
+ break;
+ case 2:
+ x -= uv_width;
+ break;
+ case 3:
+ y -= uv_height;
+ break;
+ default:
+ break;
+ }
+
+ luv->uv[0] = x;
+ luv->uv[1] = y;
+ }
+
+ x += uv_width;
+ }
+ else {
+ /* top or bottom face - so unwrap it by transforming back to a circle and using the X/Y coords */
+ BM_face_normal_update(f);
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ float uv_vco[3];
+
+ mul_v3_m4v3(uv_vco, inv_mat, l->v->co);
+
+ if (dot_v3v3(f->no, local_up) > 0.0f) { /* if this is a top face of the cone */
+ luv->uv[0] = uv_center_x_top + uv_vco[0] * uv_scale_top;
+ luv->uv[1] = uv_center_y + uv_vco[1] * uv_scale_top;
+ }
+ else {
+ luv->uv[0] = uv_center_x_bottom + uv_vco[0] * uv_scale_bottom;
+ luv->uv[1] = uv_center_y + uv_vco[1] * uv_scale_bottom;
+ }
+ }
+ }
+ }
+}
+
void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
{
BMVert *verts[8];
float mat[4][4];
float off = BMO_slot_float_get(op->slots_in, "size") / 2.0f;
+ const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
int i, x, y, z;
const char faces[6][4] = {
{1, 3, 2, 0},
@@ -693,6 +1067,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
}
for (i = 0; i < ARRAY_SIZE(faces); i++) {
+ BMFace *f;
BMVert *quad[4] = {
verts[faces[i][0]],
verts[faces[i][1]],
@@ -700,8 +1075,82 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
verts[faces[i][3]],
};
- BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true);
+ f = BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
+ }
+
+ if (calc_uvs) {
+ BM_mesh_calc_uvs_cube(bm, FACE_MARK);
}
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
+
+/**
+ * Fills first available UVmap with cube-like UVs for all faces OpFlag-ged by given flag.
+ *
+ * \note Expects tagged faces to be six quads...
+ *
+ * \param bm The BMesh to operate on.
+ * \param oflag The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag)
+{
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+ const float width = 0.25f;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ float x = 0.375f;
+ float y = 0.0f;
+
+ int loop_index;
+
+ BLI_assert(cd_loop_uv_offset != -1); /* the caller can ensure that we have UVs */
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, f, oflag)) {
+ continue;
+ }
+
+ BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ luv->uv[0] = x;
+ luv->uv[1] = y;
+
+ switch (loop_index) {
+ case 0:
+ x += width;
+ break;
+ case 1:
+ y += width;
+ break;
+ case 2:
+ x -= width;
+ break;
+ case 3:
+ y -= width;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (y >= 0.75f && x > 0.125f) {
+ x = 0.125f;
+ y = 0.5f;
+ }
+ else if (x <= 0.125f) {
+ x = 0.625f;
+ y = 0.5f;
+ }
+ else {
+ y += 0.25f;
+ }
+ }
+}
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 9fd7ec32279..c9b7875aef0 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -137,6 +137,7 @@ float ED_object_new_primitive_matrix(
void ED_object_add_unit_props(struct wmOperatorType *ot);
void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
+void ED_object_add_mesh_props(struct wmOperatorType *ot);
bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, const char view_align_axis,
float loc[3], float rot[3],
bool *enter_editmode, unsigned int *layer, bool *is_view_aligned);
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 49383356b75..b0369c6f5ad 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -29,6 +29,7 @@
* \ingroup edmesh
*/
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -49,6 +50,7 @@
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_object.h"
+#include "ED_uvedit.h"
#include "mesh_intern.h" /* own include */
@@ -105,16 +107,21 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
bool enter_editmode;
bool was_editmode;
unsigned int layer;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs && !ED_uvedit_test(obedit)) {
+ ED_mesh_uv_texture_add(obedit->data, NULL, true);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4",
- 1, 1, RNA_float_get(op->ptr, "radius"), mat))
+ "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
+ 1, 1, RNA_float_get(op->ptr, "radius"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -139,6 +146,7 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ED_object_add_unit_props(ot);
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -150,16 +158,21 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op)
bool enter_editmode;
bool was_editmode;
unsigned int layer;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs && !ED_uvedit_test(obedit)) {
+ ED_mesh_uv_texture_add(obedit->data, NULL, true);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_cube matrix=%m4 size=%f",
- mat, RNA_float_get(op->ptr, "radius") * 2.0f))
+ "create_cube matrix=%m4 size=%f calc_uvs=%b",
+ mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -185,6 +198,7 @@ void MESH_OT_primitive_cube_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ED_object_add_unit_props(ot);
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -203,6 +217,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
int cap_end, cap_tri;
unsigned int layer;
bool was_editmode;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
cap_end = RNA_enum_get(op->ptr, "fill_type");
cap_tri = (cap_end == 2);
@@ -212,11 +227,15 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs && !ED_uvedit_test(obedit)) {
+ ED_mesh_uv_texture_add(obedit->data, NULL, true);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_circle segments=%i diameter=%f cap_ends=%b cap_tris=%b matrix=%m4",
+ "create_circle segments=%i diameter=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
- cap_end, cap_tri, mat))
+ cap_end, cap_tri, mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -245,6 +264,7 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot)
ED_object_add_unit_props(ot);
RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", "");
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -259,20 +279,25 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
const bool cap_end = (end_fill_type != 0);
const bool cap_tri = (end_fill_type == 2);
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs && !ED_uvedit_test(obedit)) {
+ ED_mesh_uv_texture_add(obedit->data, NULL, true);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4",
+ "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"),
RNA_float_get(op->ptr, "radius"),
RNA_float_get(op->ptr, "radius"),
cap_end, cap_tri,
- RNA_float_get(op->ptr, "depth"), mat))
+ RNA_float_get(op->ptr, "depth"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -302,6 +327,7 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", "");
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -316,17 +342,22 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
const bool cap_end = (end_fill_type != 0);
const bool cap_tri = (end_fill_type == 2);
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs && !ED_uvedit_test(obedit)) {
+ ED_mesh_uv_texture_add(obedit->data, NULL, true);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4",
+ "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"),
- RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat))
+ RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -357,6 +388,7 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot)
RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", "");
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -368,18 +400,23 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op)
bool enter_editmode;
bool was_editmode;
unsigned int layer;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs && !ED_uvedit_test(obedit)) {
+ ED_mesh_uv_texture_add(obedit->data, NULL, true);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4",
+ "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "x_subdivisions"),
RNA_int_get(op->ptr, "y_subdivisions"),
- RNA_float_get(op->ptr, "radius"), mat))
+ RNA_float_get(op->ptr, "radius"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -410,6 +447,7 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot)
RNA_def_int(ot->srna, "y_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 2, 1000);
ED_object_add_unit_props(ot);
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -471,17 +509,22 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
bool enter_editmode;
bool was_editmode;
unsigned int layer;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs && !ED_uvedit_test(obedit)) {
+ ED_mesh_uv_texture_add(obedit->data, NULL, true);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4",
+ "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "segments"), RNA_int_get(op->ptr, "ring_count"),
- RNA_float_get(op->ptr, "size"), mat))
+ RNA_float_get(op->ptr, "size"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -510,6 +553,7 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
RNA_def_int(ot->srna, "ring_count", 16, 3, MESH_ADD_VERTS_MAXI / 100, "Rings", "", 3, 500);
RNA_def_float_distance(ot->srna, "size", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -521,17 +565,22 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
bool enter_editmode;
bool was_editmode;
unsigned int layer;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs && !ED_uvedit_test(obedit)) {
+ ED_mesh_uv_texture_add(obedit->data, NULL, true);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_icosphere subdivisions=%i diameter=%f matrix=%m4",
+ "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "subdivisions"),
- RNA_float_get(op->ptr, "size"), mat))
+ RNA_float_get(op->ptr, "size"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -559,5 +608,6 @@ void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
RNA_def_int(ot->srna, "subdivisions", 2, 1, 10, "Subdivisions", "", 1, 8);
RNA_def_float_distance(ot->srna, "size", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001f, 100.00);
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 2888077faf2..7650be941d4 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -290,6 +290,11 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+void ED_object_add_mesh_props(wmOperatorType *ot)
+{
+ RNA_def_boolean(ot->srna, "calc_uvs", false, "Generate UVs", "Generate a default UV map");
+}
+
bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view_align_axis,
float loc[3], float rot[3],
bool *enter_editmode, unsigned int *layer, bool *is_view_aligned)