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:
Diffstat (limited to 'source/blender/editors/uvedit/uvedit_ops.c')
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c252
1 files changed, 76 insertions, 176 deletions
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index a30274c0f2c..db3c994cfa0 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -47,7 +47,6 @@
#include "DNA_scene_types.h"
#include "BLI_math.h"
-#include "BLI_lasso.h"
#include "BLI_blenlib.h"
#include "BLI_array.h"
#include "BLI_utildefines.h"
@@ -523,23 +522,44 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
}
/*********************** geometric utilities ***********************/
-void uv_poly_center(BMEditMesh *em, BMFace *f, float r_cent[2])
+void poly_uv_center(BMEditMesh *em, BMFace *f, float cent[2])
{
BMLoop *l;
MLoopUV *luv;
BMIter liter;
- zero_v2(r_cent);
+ zero_v2(cent);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- add_v2_v2(r_cent, luv->uv);
+ add_v2_v2(cent, luv->uv);
}
- mul_v2_fl(r_cent, 1.0f / (float)f->len);
+ mul_v2_fl(cent, 1.0f / (float)f->len);
}
-float uv_poly_area(float uv[][2], int len)
+
+void uv_center(float uv[][2], float cent[2], int quad)
+{
+ if (quad) {
+ cent[0] = (uv[0][0] + uv[1][0] + uv[2][0] + uv[3][0]) / 4.0f;
+ cent[1] = (uv[0][1] + uv[1][1] + uv[2][1] + uv[3][1]) / 4.0f;
+ }
+ else {
+ cent[0] = (uv[0][0] + uv[1][0] + uv[2][0]) / 3.0f;
+ cent[1] = (uv[0][1] + uv[1][1] + uv[2][1]) / 3.0f;
+ }
+}
+
+float uv_area(float uv[][2], int quad)
+{
+ if (quad)
+ return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]);
+ else
+ return area_tri_v2(uv[0], uv[1], uv[2]);
+}
+
+float poly_uv_area(float uv[][2], int len)
{
//BMESH_TODO: make this not suck
//maybe use scanfill? I dunno.
@@ -552,7 +572,7 @@ float uv_poly_area(float uv[][2], int len)
return 1.0;
}
-void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
+void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
{
int i;
for (i = 0; i < len; i++) {
@@ -561,7 +581,7 @@ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float as
}
}
-int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
+int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max)
{
BMEditMesh *em = BMEdit_FromObject(obedit);
BMFace *efa;
@@ -571,7 +591,7 @@ int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], f
MLoopUV *luv;
int sel;
- INIT_MINMAX2(r_min, r_max);
+ INIT_MINMAX2(min, max);
sel = 0;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
@@ -582,7 +602,7 @@ int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], f
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_uv_select_test(em, scene, l)) {
luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- DO_MINMAX2(luv->uv, r_min, r_max);
+ DO_MINMAX2(luv->uv, min, max);
sel = 1;
}
}
@@ -643,7 +663,7 @@ static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2]
/************************** find nearest ****************************/
-void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, const float co[2], NearestHit *hit)
+void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
{
MTexPoly *tf;
BMFace *efa;
@@ -690,11 +710,13 @@ void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, const float
}
}
-static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, const float co[2], NearestHit *hit)
+static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
{
MTexPoly *tf;
BMFace *efa;
- BMIter iter;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
float mindist, dist, cent[2];
mindist = 1e10f;
@@ -709,9 +731,16 @@ static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, const
tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
if (!uvedit_face_visible_test(scene, ima, efa, tf))
continue;
+
+ cent[0] = cent[1] = 0.0f;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- uv_poly_center(em, efa, cent);
+ add_v2_v2(cent, luv->uv);
+ }
+ cent[0] /= efa->len;
+ cent[1] /= efa->len;
dist = fabs(co[0] - cent[0]) + fabs(co[1] - cent[1]);
if (dist < mindist) {
@@ -723,12 +752,12 @@ static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, const
}
static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int UNUSED(nverts), int id,
- const float co[2], const float uv[2])
+ float co[2], float uv[2])
{
BMLoop *l;
MLoopUV *luv;
BMIter iter;
- float m[3], v1[3], v2[3], c1, c2, *uv1, /* *uv2, */ /* UNUSED */ *uv3;
+ float m[3], v1[3], v2[3], c1, c2, *uv1 = NULL, /* *uv2, */ /* UNUSED */ *uv3 = NULL;
int id1, id2, i;
id1 = (id + efa->len - 1) % efa->len;
@@ -769,7 +798,7 @@ static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int UNUSED(nverts), i
}
void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
- float const co[2], const float penalty[2], NearestHit *hit)
+ float co[2], float penalty[2], NearestHit *hit)
{
BMFace *efa;
BMLoop *l;
@@ -827,7 +856,7 @@ void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
}
}
-int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2])
+int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
{
BMEditMesh *em = BMEdit_FromObject(obedit);
BMFace *efa;
@@ -836,10 +865,11 @@ int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float c
MTexPoly *tf;
MLoopUV *luv;
float mindist, dist;
- int found = FALSE;
+ int found = 0;
mindist = 1e10f;
- copy_v2_v2(r_uv, co);
+ uv[0] = co[0];
+ uv[1] = co[1];
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
@@ -853,8 +883,9 @@ int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float c
if (dist <= mindist) {
mindist = dist;
- copy_v2_v2(r_uv, luv->uv);
- found = TRUE;
+ uv[0] = luv->uv[0];
+ uv[1] = luv->uv[1];
+ found = 1;
}
}
}
@@ -1074,7 +1105,7 @@ static int select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit
/*********************** linked select ***********************/
-static void select_linked(Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], NearestHit *hit, int extend)
+static void select_linked(Scene *scene, Image *ima, BMEditMesh *em, float limit[2], NearestHit *hit, int extend)
{
BMFace *efa;
BMLoop *l;
@@ -1685,11 +1716,11 @@ static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], floa
return 0;
}
-static int mouse_select(bContext *C, const float co[2], int extend, int loop)
+static int mouse_select(bContext *C, float co[2], int extend, int loop)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ ToolSettings *ts = CTX_data_tool_settings(C);
Object *obedit = CTX_data_edit_object(C);
Image *ima = CTX_data_edit_image(C);
BMEditMesh *em = BMEdit_FromObject(obedit);
@@ -1756,8 +1787,8 @@ static int mouse_select(bContext *C, const float co[2], int extend, int loop)
}
/* mark 1 vertex as being hit */
- BLI_array_grow_items(hitv, hit.efa->len);
- BLI_array_grow_items(hituv, hit.efa->len);
+ BLI_array_growitems(hitv, hit.efa->len);
+ BLI_array_growitems(hituv, hit.efa->len);
for (i = 0; i < hit.efa->len; i++) {
hitv[i] = 0xFFFFFFFF;
}
@@ -1777,8 +1808,8 @@ static int mouse_select(bContext *C, const float co[2], int extend, int loop)
}
/* mark 2 edge vertices as being hit */
- BLI_array_grow_items(hitv, hit.efa->len);
- BLI_array_grow_items(hituv, hit.efa->len);
+ BLI_array_growitems(hitv, hit.efa->len);
+ BLI_array_growitems(hituv, hit.efa->len);
fill_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
hitv[hit.lindex] = hit.vert1;
@@ -1802,8 +1833,8 @@ static int mouse_select(bContext *C, const float co[2], int extend, int loop)
/* mark all face vertices as being hit */
- BLI_array_grow_items(hitv, hit.efa->len);
- BLI_array_grow_items(hituv, hit.efa->len);
+ BLI_array_growitems(hitv, hit.efa->len);
+ BLI_array_growitems(hituv, hit.efa->len);
i = 0;
BM_ITER_ELEM (l, &liter, hit.efa, BM_LOOPS_OF_FACE) {
luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
@@ -2091,7 +2122,7 @@ static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, i
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ ToolSettings *ts = CTX_data_tool_settings(C);
Object *obedit = CTX_data_edit_object(C);
Image *ima = CTX_data_edit_image(C);
BMEditMesh *em = BMEdit_FromObject(obedit);
@@ -2193,7 +2224,7 @@ static void UV_OT_select_linked_pick(wmOperatorType *ot)
static int unlink_selection_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ ToolSettings *ts = CTX_data_tool_settings(C);
Object *obedit = CTX_data_edit_object(C);
Image *ima = CTX_data_edit_image(C);
BMEditMesh *em = BMEdit_FromObject(obedit);
@@ -2279,7 +2310,7 @@ static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short s
*
* De-selects faces that have been tagged on efa->tmp.l. */
-static void uv_faces_do_sticky(SpaceImage *sima, Scene *scene, Object *obedit, short select)
+static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select)
{
/* Selecting UV Faces with some modes requires us to change
* the selection in other faces (depending on the sticky mode).
@@ -2287,7 +2318,7 @@ static void uv_faces_do_sticky(SpaceImage *sima, Scene *scene, Object *obedit, s
* This only needs to be done when the Mesh is not used for
* selection (so for sticky modes, vertex or location based). */
- ToolSettings *ts = scene->toolsettings;
+ ToolSettings *ts = CTX_data_tool_settings(C);
BMEditMesh *em = BMEdit_FromObject(obedit);
BMFace *efa;
BMLoop *l;
@@ -2408,7 +2439,7 @@ static int border_select_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ ToolSettings *ts = CTX_data_tool_settings(C);
Object *obedit = CTX_data_edit_object(C);
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
@@ -2457,7 +2488,7 @@ static int border_select_exec(bContext *C, wmOperator *op)
tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- uv_poly_center(em, efa, cent);
+ poly_uv_center(em, efa, cent);
if (BLI_in_rctf(&rectf, cent[0], cent[1])) {
BM_elem_flag_enable(efa, BM_ELEM_TAG);
change = 1;
@@ -2467,7 +2498,7 @@ static int border_select_exec(bContext *C, wmOperator *op)
/* (de)selects all tagged faces and deals with sticky modes */
if (change)
- uv_faces_do_sticky(sima, scene, obedit, select);
+ uv_faces_do_sticky(C, sima, scene, obedit, select);
}
else {
/* other selection modes */
@@ -2502,9 +2533,7 @@ static int border_select_exec(bContext *C, wmOperator *op)
if (change) {
uv_select_sync_flush(ts, em, select);
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -2563,7 +2592,6 @@ static int circle_select_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BMEdit_FromObject(obedit);
ARegion *ar = CTX_wm_region(C);
@@ -2601,11 +2629,9 @@ static int circle_select_exec(bContext *C, wmOperator *op)
}
if (change) {
- uv_select_sync_flush(ts, em, select);
+ uv_select_sync_flush(scene->toolsettings, em, select);
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
return OPERATOR_FINISHED;
@@ -2635,129 +2661,9 @@ static void UV_OT_circle_select(wmOperatorType *ot)
RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
}
-
-/* ******************** lasso select operator **************** */
-
-static void do_lasso_select_mesh_uv(bContext *C, int mcords[][2], short moves, short select)
-{
- Image *ima = CTX_data_edit_image(C);
- ARegion *ar = CTX_wm_region(C);
- Object *obedit = CTX_data_edit_object(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BMEdit_FromObject(obedit);
-
- BMIter iter, liter;
-
- BMFace *efa;
- BMLoop *l;
- MTexPoly *tf;
- int screen_uv[2], change = TRUE;
- rcti rect;
-
- BLI_lasso_boundbox(&rect, mcords, moves);
-
- if (ts->uv_selectmode == UV_SELECT_FACE) { /* Face Center Sel */
- change = FALSE;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* assume not touched */
- if ((select) != (uvedit_face_select_test(scene, em, efa))) {
- float cent[2];
- uv_poly_center(em, efa, cent);
- UI_view2d_view_to_region(&ar->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]);
- if (BLI_in_rcti(&rect, screen_uv[0], screen_uv[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
- {
- uvedit_face_select_enable(scene, em, efa, FALSE);
- change = TRUE;
- }
- }
- }
- }
- else { /* Vert Sel */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if ((select) != (uvedit_uv_select_test(em, scene, l))) {
- MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- UI_view2d_view_to_region(&ar->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]);
- if (BLI_in_rcti(&rect, screen_uv[0], screen_uv[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
- {
- if (select) {
- uvedit_uv_select_enable(em, scene, l, FALSE);
- }
- else {
- uvedit_uv_select_disable(em, scene, l);
- }
- }
- }
- }
- }
- }
- }
- if (change) {
- uv_select_sync_flush(scene->toolsettings, em, select);
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
- }
-}
-
-static int uv_lasso_select_exec(bContext *C, wmOperator *op)
-{
- int i = 0;
- int mcords[1024][2];
-
- RNA_BEGIN (op->ptr, itemptr, "path") {
- float loc[2];
-
- RNA_float_get_array(&itemptr, "loc", loc);
- mcords[i][0] = (int)loc[0];
- mcords[i][1] = (int)loc[1];
- i++;
- if (i >= 1024) break;
- }
- RNA_END;
-
- if (i > 1) {
- short select;
-
- select = !RNA_boolean_get(op->ptr, "deselect");
- do_lasso_select_mesh_uv(C, mcords, i, select);
-
- return OPERATOR_FINISHED;
- }
- return OPERATOR_PASS_THROUGH;
-}
-
-void UV_OT_select_lasso(wmOperatorType *ot)
-{
- ot->name = "Lasso Select UV";
- ot->description = "Select UVs using lasso selection";
- ot->idname = "UV_OT_select_lasso";
-
- ot->invoke = WM_gesture_lasso_invoke;
- ot->modal = WM_gesture_lasso_modal;
- ot->exec = uv_lasso_select_exec;
- ot->poll = ED_operator_image_active;
- ot->cancel = WM_gesture_lasso_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
- RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
- RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
-}
-
-
-
/* ******************** snap cursor operator **************** */
-static void snap_uv_to_pixel(float uvco[2], float w, float h)
+static void snap_uv_to_pixel(float *uvco, float w, float h)
{
uvco[0] = ((float)((int)((uvco[0] * w) + 0.5f))) / w;
uvco[1] = ((float)((int)((uvco[1] * h) + 0.5f))) / h;
@@ -3122,9 +3028,9 @@ static int bm_face_is_all_uv_sel(BMesh *bm, BMFace *f, int bool_test)
static int hide_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BMEdit_FromObject(obedit);
BMFace *efa;
BMLoop *l;
@@ -3237,9 +3143,9 @@ static void UV_OT_hide(wmOperatorType *ot)
static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceImage *sima = CTX_wm_space_image(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
Object *obedit = CTX_data_edit_object(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ /*Scene *scene = CTX_data_scene(C);*/ /*UNUSED*/
BMEditMesh *em = BMEdit_FromObject(obedit);
BMFace *efa;
BMLoop *l;
@@ -3665,7 +3571,6 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_unlink_selected);
WM_operatortype_append(UV_OT_select_pinned);
WM_operatortype_append(UV_OT_select_border);
- WM_operatortype_append(UV_OT_select_lasso);
WM_operatortype_append(UV_OT_circle_select);
WM_operatortype_append(UV_OT_snap_cursor);
@@ -3726,11 +3631,6 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "UV_OT_circle_select", CKEY, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "deselect", FALSE);
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", TRUE);
-
/* selection manipulation */
RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0)->ptr, "extend", FALSE);
RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0)->ptr, "extend", FALSE);