diff --git a/source/blender/blenlib/BLI_boxpack2d.h b/source/blender/blenlib/BLI_boxpack2d.h new file mode 100644 index 00000000000..b5cf9cd81e9 --- /dev/null +++ b/source/blender/blenlib/BLI_boxpack2d.h @@ -0,0 +1,69 @@ +/** + * + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + * The old math stuff from Ton. These will slowly phase out in favour + * of MTC calls. (or even MoTO :) ) + * */ + +/* Box Packer */ + +/* verts, internal use only */ +typedef struct boxVert { + float x; + float y; + short free; + + struct boxPack *trb; /* top right box */ + struct boxPack *blb; /* bottom left box */ + struct boxPack *brb; /* bottom right box */ + struct boxPack *tlb; /* top left box */ + + /* Store last intersecting boxes here + * speedup intersection testing */ + struct boxPack *isect_cache[4]; + + int index; +} boxVert; + +typedef struct boxPack { + float x; + float y; + float w; + float h; + int index; + + /* Verts this box uses + * (BL,TR,TL,BR) / 0,1,2,3 */ + boxVert *v[4]; +} boxPack; + +void boxPack2D(boxPack *boxarray, int len, float *tot_width, float *tot_height); + diff --git a/source/blender/blenlib/intern/boxpack2d.c b/source/blender/blenlib/intern/boxpack2d.c new file mode 100644 index 00000000000..ad90df650e2 --- /dev/null +++ b/source/blender/blenlib/intern/boxpack2d.c @@ -0,0 +1,372 @@ +/* + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Campbell barton + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BKE_utildefines.h" +#include "MEM_guardedalloc.h" +#include "BLI_boxpack2d.h" + +/* Campbells BoxPacker ported from Python */ +/* free vert flags */ +#define EUL 0.0000001 +#define BLF 1 +#define TRF 2 +#define TLF 4 +#define BRF 8 +#define BL 0 +#define TR 1 +#define TL 2 +#define BR 3 + +#define BOXLEFT(b) b->v[BL]->x +#define BOXRIGHT(b) b->v[TR]->x +#define BOXBOTTOM(b) b->v[BL]->y +#define BOXTOP(b) b->v[TR]->y +#define BOXAREA(b) (b->w * b->h) + +#define UPDATE_V34X(b) b->v[TL]->x = b->v[BL]->x; b->v[BR]->x = b->v[TR]->x +#define UPDATE_V34Y(b) b->v[TL]->y = b->v[TR]->y; b->v[BR]->y = b->v[BL]->y + +#define UPDATE_V34(b) UPDATE_V34X(b) UPDATE_V34Y(b) + +#define SET_BOXLEFT(b, f) b->v[TR]->x = f + b->w; b->v[BL]->x = f; UPDATE_V34X(b) +#define SET_BOXRIGHT(b, f) b->v[BL]->x = f - b->w; b->v[TR]->x = f; UPDATE_V34X(b) +#define SET_BOXBOTTOM(b, f) b->v[TR]->y = f + b->h; b->v[BL]->y = f; UPDATE_V34Y(b) +#define SET_BOXTOP(b, f) b->v[BL]->y = f - b->h; b->v[TR]->y = f; UPDATE_V34Y(b) +#define BOXINTERSECT(b1, b2) (!(BOXLEFT(b1)+EUL>=BOXRIGHT(b2) || BOXBOTTOM(b1)+EUL>=BOXTOP(b2) || BOXRIGHT(b1)-EUL<=BOXLEFT(b2) || BOXTOP(b1)-EUL<=BOXBOTTOM(b2) )) + +/* #define BOXDEBUG(b) printf("\tBox Debug i %i, w:%.3f h:%.3f x:%.3f y:%.3f\n", b->index, b->w, b->h, b->x, b->y) */ + + +static int box_areasort(const void *p1, const void *p2) +{ + const boxPack *b1=p1, *b2=p2; + float a1, a2; + + a1 = BOXAREA(b1); + a2 = BOXAREA(b2); + + /* sort largest to smallest */ + if ( a1 < a2 ) return 1; + else if ( a1 > a2 ) return -1; + return 0; +} + + +static float box_width; +static float box_height; +static boxVert *vertarray; + +static int vertex_sort(const void *p1, const void *p2) +{ + boxVert *v1, *v2; + float a1, a2; + + v1 = vertarray + ((int *) p1)[0]; + v2 = vertarray + ((int *) p2)[0]; + + a1 = MAX2(v1->x+box_width, v1->y+box_height); + a2 = MAX2(v2->x+box_width, v2->y+box_height); + + /* sort largest to smallest */ + if ( a1 > a2 ) return 1; + else if ( a1 < a2 ) return -1; + return 0; +} + +void boxPack2D(boxPack *boxarray, int len, float *tot_width, float *tot_height) +{ + boxVert *vert; + int box_index, verts_pack_len, i, j, k, isect; /* what box are we up to packing */ + int quad_flags[4]= {BLF,TRF,TLF,BRF}; /* use for looping */ + boxPack *box, *box_test; + int *vertex_pack_indicies; + + if (!len) { + *tot_width = 0.0; + *tot_height = 0.0; + return; + } + + /* Sort boxes, biggest first */ + qsort(boxarray, len, sizeof(boxPack), box_areasort); + + /* add verts to the boxes, these are only used internally */ + vert = vertarray = MEM_mallocN( len*4*sizeof(boxVert), "boxPack verts"); + vertex_pack_indicies = MEM_mallocN( len*3*sizeof(int), "boxPack indicies"); + i=0; + for (box= boxarray, box_index= 0; box_index < len; box_index++, box++) { + + vert->blb = vert->brb = vert->tlb =\ + vert->isect_cache[0] = vert->isect_cache[1] =\ + vert->isect_cache[2] = vert->isect_cache[3] = NULL; + vert->free = 15 &~ TRF; + vert->trb = box; + vert->index = i; i++; + box->v[BL] = vert; vert++; + + vert->trb= vert->brb = vert->tlb =\ + vert->isect_cache[0] = vert->isect_cache[1] =\ + vert->isect_cache[2] = vert->isect_cache[3] = NULL; + vert->free = 15 &~ BLF; + vert->blb = box; + vert->index = i; i++; + box->v[TR] = vert; vert++; + + vert->trb = vert->blb = vert->tlb =\ + vert->isect_cache[0] = vert->isect_cache[1] =\ + vert->isect_cache[2] = vert->isect_cache[3] = NULL; + vert->free = 15 &~ BRF; + vert->brb = box; + vert->index = i; i++; + box->v[TL] = vert; vert++; + + vert->trb = vert->blb = vert->brb =\ + vert->isect_cache[0] = vert->isect_cache[1] =\ + vert->isect_cache[2] = vert->isect_cache[3] = NULL; + vert->free = 15 &~ TLF; + vert->tlb = box; + vert->index = i; i++; + box->v[BR] = vert; vert++; + } + vert = NULL; + + + /* Pack the First box! + * then enter the main boxpacking loop */ + + box = boxarray; /* get the first box */ + /* First time, no boxes packed */ + box->v[BL]->free = 0; /* Cant use any if these */ + box->v[BR]->free &= ~(BLF|BRF); + box->v[TL]->free &= ~(BLF|TLF); + + *tot_width = box->w; + *tot_height = box->h; + + /* This sets all the vertex locations */ + SET_BOXLEFT(box, 0.0); + SET_BOXBOTTOM(box, 0.0); + + for (i=0; i<3; i++) + vertex_pack_indicies[i] = box->v[i+1]->index; + verts_pack_len = 3; + box++; /* next box, needed for the loop below */ + /* ...done packing the first box */ + + /* Main boxpacking loop */ + for (box_index=1; box_index < len; box_index++, box++) { + + /* Sort the verts, these constants are used in sorting */ + box_width = box->w; + box_height = box->h; + + qsort(vertex_pack_indicies, verts_pack_len, sizeof(int), vertex_sort); + + /* Pack the box in with the others */ + /* sort the verts */ + isect = 1; + + for (i=0; ifree, verts_pack_len, vert->x, vert->y); */ + + /* This vert has a free quaderent + * Test if we can place the box here + * vert->free & quad_flags[j] - Checks + * */ + + for (j=0; (j<4) && isect; j++) { + if (vert->free & quad_flags[j]) { + switch (j) { + case BL: + SET_BOXRIGHT(box, vert->x); + SET_BOXTOP(box, vert->y); + break; + case TR: + SET_BOXLEFT(box, vert->x); + SET_BOXBOTTOM(box, vert->y); + break; + case TL: + SET_BOXRIGHT(box, vert->x); + SET_BOXBOTTOM(box, vert->y); + break; + case BR: + SET_BOXLEFT(box, vert->x); + SET_BOXTOP(box, vert->y); + break; + } + + /* Now we need to check that the box intersects + * with any other boxes + * Assume no intersection... */ + isect = 0; + + if (/* Constrain boxes to positive X/Y values */ + BOXLEFT(box)<0.0 || BOXBOTTOM(box)<0.0 || + /* check for last intersected */ + (vert->isect_cache[j] && BOXINTERSECT(box, vert->isect_cache[j])) + ) { + /* Here we check that the last intersected + * box will intersect with this one using + * isect_cache that can store a pointer to a + * box for each quaderent + * big speedup */ + isect = 1; + } else { + /* do a full saech for colliding box + * this is realy slow, some spacialy divided + * datastructure would be better */ + for (box_test = boxarray; box_test != box; box_test++) { + if BOXINTERSECT(box, box_test) { + /* Store the last intersecting here + * as cache for faster checking next time around */ + vert->isect_cache[j] = box_test; + isect = 1; + break; + } + } + } + + if (!isect) { + + /* maintain the total width and height */ + (*tot_width) = MAX2(BOXRIGHT(box), (*tot_width)); + (*tot_height) = MAX2(BOXTOP(box), (*tot_height)); + + /* Place the box */ + vert->free &= ~quad_flags[j]; + + switch (j) { + case TR: + box->v[BL]= vert; + vert->trb = box; + break; + case TL: + box->v[BR]= vert; + vert->tlb = box; + break; + case BR: + box->v[TL]= vert; + vert->brb = box; + break; + case BL: + box->v[TR]= vert; + vert->blb = box; + break; + } + + /* Mask free flags for verts that are on the bottom or side + * so we dont get boxes outside the given rectangle ares + * + * We can do an else/if here because only the first + * box can be at the very bottom left corner */ + if (BOXLEFT(box) <= 0) { + box->v[TL]->free &= ~(TLF|BLF); + box->v[BL]->free &= ~(TLF|BLF); + } else if (BOXBOTTOM(box) <= 0) { + box->v[BL]->free &= ~(BRF|BLF); + box->v[BR]->free &= ~(BRF|BLF); + } + + /* The following block of code does a logical + * check with 2 adjacent boxes, its possible to + * flag verts on one or both of the boxes + * as being used by checking the width or + * height of both boxes */ + if (vert->tlb && vert->trb && (box == vert->tlb || box == vert->trb)) { + if (vert->tlb->h > vert->trb->h) { + vert->trb->v[TL]->free &= ~(TLF|BLF); + } else if (vert->tlb->h < vert->trb->h) { + vert->tlb->v[TR]->free &= ~(TRF|BRF); + } else { /*same*/ + vert->tlb->v[TR]->free &= ~BLF; + vert->trb->v[TL]->free &= ~BRF; + } + } else if (vert->blb && vert->brb && (box == vert->blb || box == vert->brb)) { + if (vert->blb->h > vert->brb->h) { + vert->brb->v[BL]->free &= ~(TLF|BLF); + } else if (vert->blb->h < vert->brb->h) { + vert->blb->v[BR]->free &= ~(TRF|BRF); + } else { /*same*/ + vert->blb->v[BR]->free &= ~TRF; + vert->brb->v[BL]->free &= ~TLF; + } + } + /* Horizontal */ + if (vert->tlb && vert->blb && (box == vert->tlb || box == vert->blb)) { + if (vert->tlb->w > vert->blb->w) { + vert->blb->v[TL]->free &= ~(TLF|TRF); + } else if (vert->tlb->w < vert->blb->w) { + vert->tlb->v[BL]->free &= ~(BLF|BRF); + } else { /*same*/ + vert->blb->v[TL]->free &= ~TRF; + vert->tlb->v[BL]->free &= ~BRF; + } + } else if (vert->trb && vert->brb && (box == vert->trb || box == vert->brb)) { + if (vert->trb->w > vert->brb->w) { + vert->brb->v[TR]->free &= ~(TRF|TRF); + } else if (vert->trb->w < vert->brb->w) { + vert->trb->v[BR]->free &= ~(BLF|BRF); + } else { /*same*/ + vert->brb->v[TR]->free &= ~TLF; + vert->trb->v[BR]->free &= ~BLF; + } + } + /* End logical check */ + + + for (k=0; k<4; k++) { + if (box->v[k] != vert) { + vertex_pack_indicies[verts_pack_len] = box->v[k]->index; + verts_pack_len++; + } + } + /* The Box verts are only used interially + * Update the box x and y since thats what external + * functions will see */ + box->x = BOXLEFT(box); + box->y = BOXBOTTOM(box); + } + } + } + } + } + + /* free all the verts, not realy needed because they shouldebt be + * touched anymore but accessing the pointers woud crash blender */ + for (box_index=0; box_index < len; box_index++) { + box = boxarray+box_index; + box->v[0] = box->v[1] = box->v[2] = box->v[3] = NULL; + } + MEM_freeN(vertex_pack_indicies); + MEM_freeN(vertarray); +} + diff --git a/source/blender/python/api2_2x/Geometry.c b/source/blender/python/api2_2x/Geometry.c index c1bdf47a368..4504c2d5d29 100644 --- a/source/blender/python/api2_2x/Geometry.c +++ b/source/blender/python/api2_2x/Geometry.c @@ -39,13 +39,14 @@ /* Used for PolyFill */ #include "BKE_displist.h" -#include "MEM_guardedalloc.h" +#include "MEM_guardedalloc.h" #include "BLI_blenlib.h" /* needed for EXPP_ReturnPyObjError and EXPP_check_sequence_consistency */ #include "gen_utils.h" #include "BKE_utildefines.h" +#include "BLI_boxpack2d.h" #define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp #define eul 0.000001 @@ -273,345 +274,6 @@ static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args ) Py_RETURN_NONE; } - - -/* Campbells BoxPacker ported from Python */ -/* free vert flags */ -#define EUL 0.0000001 -#define BLF 1 -#define TRF 2 -#define TLF 4 -#define BRF 8 -#define BL 0 -#define TR 1 -#define TL 2 -#define BR 3 - -#define BOXLEFT(b) b->v[BL]->x -#define BOXRIGHT(b) b->v[TR]->x -#define BOXBOTTOM(b) b->v[BL]->y -#define BOXTOP(b) b->v[TR]->y -#define BOXAREA(b) (b->w * b->h) - -#define UPDATE_V34X(b) b->v[TL]->x = b->v[BL]->x; b->v[BR]->x = b->v[TR]->x -#define UPDATE_V34Y(b) b->v[TL]->y = b->v[TR]->y; b->v[BR]->y = b->v[BL]->y - -#define UPDATE_V34(b) UPDATE_V34X(b) UPDATE_V34Y(b) - -#define SET_BOXLEFT(b, f) b->v[TR]->x = f + b->w; b->v[BL]->x = f; UPDATE_V34X(b) -#define SET_BOXRIGHT(b, f) b->v[BL]->x = f - b->w; b->v[TR]->x = f; UPDATE_V34X(b) -#define SET_BOXBOTTOM(b, f) b->v[TR]->y = f + b->h; b->v[BL]->y = f; UPDATE_V34Y(b) -#define SET_BOXTOP(b, f) b->v[BL]->y = f - b->h; b->v[TR]->y = f; UPDATE_V34Y(b) -#define BOXINTERSECT(b1, b2) (!(BOXLEFT(b1)+EUL>=BOXRIGHT(b2) || BOXBOTTOM(b1)+EUL>=BOXTOP(b2) || BOXRIGHT(b1)-EUL<=BOXLEFT(b2) || BOXTOP(b1)-EUL<=BOXBOTTOM(b2) )) - -/* #define BOXDEBUG(b) printf("\tBox Debug i %i, w:%.3f h:%.3f x:%.3f y:%.3f\n", b->index, b->w, b->h, b->x, b->y) */ - - -static int box_areasort(const void *p1, const void *p2) -{ - const boxPack *b1=p1, *b2=p2; - float a1, a2; - - a1 = BOXAREA(b1); - a2 = BOXAREA(b2); - - /* sort largest to smallest */ - if ( a1 < a2 ) return 1; - else if ( a1 > a2 ) return -1; - return 0; -} - - -static float box_width; -static float box_height; -static boxVert *vertarray; - -static int vertex_sort(const void *p1, const void *p2) -{ - boxVert *v1, *v2; - float a1, a2; - - v1 = vertarray + ((int *) p1)[0]; - v2 = vertarray + ((int *) p2)[0]; - - a1 = MAX2(v1->x+box_width, v1->y+box_height); - a2 = MAX2(v2->x+box_width, v2->y+box_height); - - /* sort largest to smallest */ - if ( a1 > a2 ) return 1; - else if ( a1 < a2 ) return -1; - return 0; -} - -static void boxPackAll(boxPack *boxarray, int len, float *tot_width, float *tot_height) -{ - boxVert *vert; - int box_index, verts_pack_len, i, j, k, isect; /* what box are we up to packing */ - int quad_flags[4]= {BLF,TRF,TLF,BRF}; /* use for looping */ - boxPack *box, *box_test; - int *vertex_pack_indicies; - - if (!len) { - *tot_width = 0.0; - *tot_height = 0.0; - return; - } - - /* Sort boxes, biggest first */ - qsort(boxarray, len, sizeof(boxPack), box_areasort); - - /* add verts to the boxes, these are only used internally */ - vert = vertarray = MEM_mallocN( len*4*sizeof(boxVert), "boxPack verts"); - vertex_pack_indicies = MEM_mallocN( len*3*sizeof(int), "boxPack indicies"); - i=0; - for (box= boxarray, box_index= 0; box_index < len; box_index++, box++) { - - vert->blb = vert->brb = vert->tlb =\ - vert->isect_cache[0] = vert->isect_cache[1] =\ - vert->isect_cache[2] = vert->isect_cache[3] = NULL; - vert->free = 15 &~ TRF; - vert->trb = box; - vert->index = i; i++; - box->v[BL] = vert; vert++; - - vert->trb= vert->brb = vert->tlb =\ - vert->isect_cache[0] = vert->isect_cache[1] =\ - vert->isect_cache[2] = vert->isect_cache[3] = NULL; - vert->free = 15 &~ BLF; - vert->blb = box; - vert->index = i; i++; - box->v[TR] = vert; vert++; - - vert->trb = vert->blb = vert->tlb =\ - vert->isect_cache[0] = vert->isect_cache[1] =\ - vert->isect_cache[2] = vert->isect_cache[3] = NULL; - vert->free = 15 &~ BRF; - vert->brb = box; - vert->index = i; i++; - box->v[TL] = vert; vert++; - - vert->trb = vert->blb = vert->brb =\ - vert->isect_cache[0] = vert->isect_cache[1] =\ - vert->isect_cache[2] = vert->isect_cache[3] = NULL; - vert->free = 15 &~ TLF; - vert->tlb = box; - vert->index = i; i++; - box->v[BR] = vert; vert++; - } - vert = NULL; - - - /* Pack the First box! - * then enter the main boxpacking loop */ - - box = boxarray; /* get the first box */ - /* First time, no boxes packed */ - box->v[BL]->free = 0; /* Cant use any if these */ - box->v[BR]->free &= ~(BLF|BRF); - box->v[TL]->free &= ~(BLF|TLF); - - *tot_width = box->w; - *tot_height = box->h; - - /* This sets all the vertex locations */ - SET_BOXLEFT(box, 0.0); - SET_BOXBOTTOM(box, 0.0); - - for (i=0; i<3; i++) - vertex_pack_indicies[i] = box->v[i+1]->index; - verts_pack_len = 3; - box++; /* next box, needed for the loop below */ - /* ...done packing the first box */ - - /* Main boxpacking loop */ - for (box_index=1; box_index < len; box_index++, box++) { - - /* Sort the verts, these constants are used in sorting */ - box_width = box->w; - box_height = box->h; - - qsort(vertex_pack_indicies, verts_pack_len, sizeof(int), vertex_sort); - - /* Pack the box in with the others */ - /* sort the verts */ - isect = 1; - - for (i=0; ifree, verts_pack_len, vert->x, vert->y); */ - - /* This vert has a free quaderent - * Test if we can place the box here - * vert->free & quad_flags[j] - Checks - * */ - - for (j=0; (j<4) && isect; j++) { - if (vert->free & quad_flags[j]) { - switch (j) { - case BL: - SET_BOXRIGHT(box, vert->x); - SET_BOXTOP(box, vert->y); - break; - case TR: - SET_BOXLEFT(box, vert->x); - SET_BOXBOTTOM(box, vert->y); - break; - case TL: - SET_BOXRIGHT(box, vert->x); - SET_BOXBOTTOM(box, vert->y); - break; - case BR: - SET_BOXLEFT(box, vert->x); - SET_BOXTOP(box, vert->y); - break; - } - - /* Now we need to check that the box intersects - * with any other boxes - * Assume no intersection... */ - isect = 0; - - if (/* Constrain boxes to positive X/Y values */ - BOXLEFT(box)<0.0 || BOXBOTTOM(box)<0.0 || - /* check for last intersected */ - (vert->isect_cache[j] && BOXINTERSECT(box, vert->isect_cache[j])) - ) { - /* Here we check that the last intersected - * box will intersect with this one using - * isect_cache that can store a pointer to a - * box for each quaderent - * big speedup */ - isect = 1; - } else { - /* do a full saech for colliding box - * this is realy slow, some spacialy divided - * datastructure would be better */ - for (box_test = boxarray; box_test != box; box_test++) { - if BOXINTERSECT(box, box_test) { - /* Store the last intersecting here - * as cache for faster checking next time around */ - vert->isect_cache[j] = box_test; - isect = 1; - break; - } - } - } - - if (!isect) { - - /* maintain the total width and height */ - (*tot_width) = MAX2(BOXRIGHT(box), (*tot_width)); - (*tot_height) = MAX2(BOXTOP(box), (*tot_height)); - - /* Place the box */ - vert->free &= ~quad_flags[j]; - - switch (j) { - case TR: - box->v[BL]= vert; - vert->trb = box; - break; - case TL: - box->v[BR]= vert; - vert->tlb = box; - break; - case BR: - box->v[TL]= vert; - vert->brb = box; - break; - case BL: - box->v[TR]= vert; - vert->blb = box; - break; - } - - /* Mask free flags for verts that are on the bottom or side - * so we dont get boxes outside the given rectangle ares - * - * We can do an else/if here because only the first - * box can be at the very bottom left corner */ - if (BOXLEFT(box) <= 0) { - box->v[TL]->free &= ~(TLF|BLF); - box->v[BL]->free &= ~(TLF|BLF); - } else if (BOXBOTTOM(box) <= 0) { - box->v[BL]->free &= ~(BRF|BLF); - box->v[BR]->free &= ~(BRF|BLF); - } - - /* The following block of code does a logical - * check with 2 adjacent boxes, its possible to - * flag verts on one or both of the boxes - * as being used by checking the width or - * height of both boxes */ - if (vert->tlb && vert->trb && (box == vert->tlb || box == vert->trb)) { - if (vert->tlb->h > vert->trb->h) { - vert->trb->v[TL]->free &= ~(TLF|BLF); - } else if (vert->tlb->h < vert->trb->h) { - vert->tlb->v[TR]->free &= ~(TRF|BRF); - } else { /*same*/ - vert->tlb->v[TR]->free &= ~BLF; - vert->trb->v[TL]->free &= ~BRF; - } - } else if (vert->blb && vert->brb && (box == vert->blb || box == vert->brb)) { - if (vert->blb->h > vert->brb->h) { - vert->brb->v[BL]->free &= ~(TLF|BLF); - } else if (vert->blb->h < vert->brb->h) { - vert->blb->v[BR]->free &= ~(TRF|BRF); - } else { /*same*/ - vert->blb->v[BR]->free &= ~TRF; - vert->brb->v[BL]->free &= ~TLF; - } - } - /* Horizontal */ - if (vert->tlb && vert->blb && (box == vert->tlb || box == vert->blb)) { - if (vert->tlb->w > vert->blb->w) { - vert->blb->v[TL]->free &= ~(TLF|TRF); - } else if (vert->tlb->w < vert->blb->w) { - vert->tlb->v[BL]->free &= ~(BLF|BRF); - } else { /*same*/ - vert->blb->v[TL]->free &= ~TRF; - vert->tlb->v[BL]->free &= ~BRF; - } - } else if (vert->trb && vert->brb && (box == vert->trb || box == vert->brb)) { - if (vert->trb->w > vert->brb->w) { - vert->brb->v[TR]->free &= ~(TRF|TRF); - } else if (vert->trb->w < vert->brb->w) { - vert->trb->v[BR]->free &= ~(BLF|BRF); - } else { /*same*/ - vert->brb->v[TR]->free &= ~TLF; - vert->trb->v[BR]->free &= ~BLF; - } - } - /* End logical check */ - - - for (k=0; k<4; k++) { - if (box->v[k] != vert) { - vertex_pack_indicies[verts_pack_len] = box->v[k]->index; - verts_pack_len++; - } - } - /* The Box verts are only used interially - * Update the box x and y since thats what external - * functions will see */ - box->x = BOXLEFT(box); - box->y = BOXBOTTOM(box); - } - } - } - } - } - - /* free all the verts, not realy needed because they shouldebt be - * touched anymore but accessing the pointers woud crash blender */ - for (box_index=0; box_index < len; box_index++) { - box = boxarray+box_index; - box->v[0] = box->v[1] = box->v[2] = box->v[3] = NULL; - } - MEM_freeN(vertex_pack_indicies); - MEM_freeN(vertarray); -} - int boxPack_FromPyObject(PyObject * value, boxPack **boxarray ) { int len, i; @@ -648,7 +310,6 @@ int boxPack_FromPyObject(PyObject * value, boxPack **boxarray ) "can only back a list of 2d boxes [x,y,x,w]" ); } - box->x = box->y = 0.0f; box->w = (float)PyFloat_AsDouble( item_1 ); box->h = (float)PyFloat_AsDouble( item_2 ); box->index = i; @@ -697,7 +358,7 @@ static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * args ) if (error!=0) return NULL; /* Non Python function */ - boxPackAll(boxarray, len, &tot_width, &tot_height); + boxPack2D(boxarray, len, &tot_width, &tot_height); boxPack_ToPyObject(boxlist, &boxarray); diff --git a/source/blender/python/api2_2x/Geometry.h b/source/blender/python/api2_2x/Geometry.h index 09a1a27800e..c74f832c642 100644 --- a/source/blender/python/api2_2x/Geometry.h +++ b/source/blender/python/api2_2x/Geometry.h @@ -39,37 +39,4 @@ PyObject *Geometry_Init( void ); - -/* Box Packer */ -typedef struct boxVert { - float x; - float y; - short free; - - struct boxPack *trb; /* top right box */ - struct boxPack *blb; /* bottom left box */ - struct boxPack *brb; /* bottom right box */ - struct boxPack *tlb; /* top left box */ - - /* Store last intersecting boxes here - * speedup intersection testing */ - struct boxPack *isect_cache[4]; - - int index; -} boxVert; - - -typedef struct boxPack { - float x; - float y; - float w; - float h; - int index; - - /* Verts this box uses - * (BL,TR,TL,BR) / 0,1,2,3 */ - boxVert *v[4]; -} boxPack; - - #endif /* EXPP_Geometry_H */ diff --git a/source/blender/src/parametrizer.c b/source/blender/src/parametrizer.c index 22282922b34..d47925a97cd 100644 --- a/source/blender/src/parametrizer.c +++ b/source/blender/src/parametrizer.c @@ -5,6 +5,7 @@ #include "BLI_arithb.h" #include "BLI_rand.h" #include "BLI_heap.h" +#include "BLI_boxpack2d.h" #include "BKE_utildefines.h" @@ -211,23 +212,6 @@ static float p_face_uv_area_signed(PFace *f) ((v3->uv[0] - v1->uv[0])*(v2->uv[1] - v1->uv[1]))); } -static float p_face_uv_area(PFace *f) -{ - return fabs(p_face_uv_area_signed(f)); -} - -static void p_chart_area(PChart *chart, float *uv_area, float *area) -{ - PFace *f; - - *uv_area = *area = 0.0f; - - for (f=chart->faces; f; f=f->nextlink) { - *uv_area += p_face_uv_area(f); - *area += p_face_area(f); - } -} - static float p_edge_length(PEdge *e) { PVert *v1 = e->vert, *v2 = e->next->vert; @@ -3104,144 +3088,6 @@ static void p_chart_stretch_minimize(PChart *chart, RNG *rng) } } -/* Packing */ - -static int p_compare_chart_area(const void *a, const void *b) -{ - PChart *ca = *((PChart**)a); - PChart *cb = *((PChart**)b); - - if (ca->u.pack.area > cb->u.pack.area) - return -1; - else if (ca->u.pack.area == cb->u.pack.area) - return 0; - else - return 1; -} - -static PBool p_pack_try(PHandle *handle, float side) -{ - PChart *chart; - float packx, packy, rowh, groupw, w, h; - int i; - - packx= packy= 0.0; - rowh= 0.0; - groupw= 1.0/sqrt(handle->ncharts); - - for (i = 0; i < handle->ncharts; i++) { - chart = handle->charts[i]; - - if (chart->flag & PCHART_NOPACK) - continue; - - w = chart->u.pack.size[0]; - h = chart->u.pack.size[1]; - - if(w <= (side-packx)) { - chart->u.pack.trans[0] = packx; - chart->u.pack.trans[1] = packy; - - packx += w; - rowh= MAX2(rowh, h); - } - else { - packy += rowh; - packx = w; - rowh = h; - - chart->u.pack.trans[0] = 0.0; - chart->u.pack.trans[1] = packy; - } - - if (packy+rowh > side) - return P_FALSE; - } - - return P_TRUE; -} - -#define PACK_SEARCH_DEPTH 15 - -void p_charts_pack(PHandle *handle) -{ - PChart *chart; - float uv_area, area, trans[2], minside, maxside, totarea, side; - int i; - - /* very simple rectangle packing */ - - if (handle->ncharts == 0) - return; - - totarea = 0.0f; - maxside = 0.0f; - - for (i = 0; i < handle->ncharts; i++) { - chart = handle->charts[i]; - - if (chart->flag & PCHART_NOPACK) { - chart->u.pack.area = 0.0f; - continue; - } - - p_chart_area(chart, &uv_area, &area); - p_chart_uv_bbox(chart, trans, chart->u.pack.size); - - /* translate to origin and make area equal to 3d area */ - chart->u.pack.rescale = (uv_area > 0.0f)? sqrt(area)/sqrt(uv_area): 0.0f; - chart->u.pack.area = area; - totarea += area; - - trans[0] = -trans[0]; - trans[1] = -trans[1]; - p_chart_uv_translate(chart, trans); - p_chart_uv_scale(chart, chart->u.pack.rescale); - - /* compute new dimensions for packing */ - chart->u.pack.size[0] += trans[0]; - chart->u.pack.size[1] += trans[1]; - chart->u.pack.size[0] *= chart->u.pack.rescale; - chart->u.pack.size[1] *= chart->u.pack.rescale; - - maxside = MAX3(maxside, chart->u.pack.size[0], chart->u.pack.size[1]); - } - - /* sort by chart area, largest first */ - qsort(handle->charts, handle->ncharts, sizeof(PChart*), p_compare_chart_area); - - /* binary search over pack region size */ - minside = MAX2(sqrt(totarea), maxside); - maxside = (((int)sqrt(handle->ncharts-1))+1)*maxside; - - if (minside < maxside) { /* should always be true */ - - for (i = 0; i < PACK_SEARCH_DEPTH; i++) { - if (p_pack_try(handle, (minside+maxside)*0.5f + 1e-5)) - maxside = (minside+maxside)*0.5f; - else - minside = (minside+maxside)*0.5f; - } - } - - /* do the actual packing */ - side = maxside + 1e-5; - if (!p_pack_try(handle, side)) - param_warning("packing failed.\n"); - - for (i = 0; i < handle->ncharts; i++) { - chart = handle->charts[i]; - - if (chart->flag & PCHART_NOPACK) - continue; - - p_chart_uv_scale(chart, 1.0f/side); - trans[0] = chart->u.pack.trans[0]/side; - trans[1] = chart->u.pack.trans[1]/side; - p_chart_uv_translate(chart, trans); - } -} - /* Minimum area enclosing rectangle for packing */ static int p_compare_geometric_uv(const void *a, const void *b) @@ -4242,10 +4088,66 @@ void param_smooth_area(ParamHandle *handle) p_smooth(chart); } } - + void param_pack(ParamHandle *handle) { - p_charts_pack((PHandle*)handle); + /* box packing variables */ + boxPack *boxarray, *box; + float tot_width, tot_height, scale; + + PChart *chart; + int i, unpacked=0; + float trans[2]; + + PHandle *phandle = (PHandle*)handle; + + + if (phandle->ncharts == 0) + return; + + /* we may not use all these boxes */ + boxarray = MEM_mallocN( phandle->ncharts*sizeof(boxPack), "boxPack box"); + + for (i = 0; i < phandle->ncharts; i++) { + chart = phandle->charts[i]; + + + if (chart->flag & PCHART_NOPACK) { + unpacked++; + continue; + } + + box = boxarray+(i-unpacked); + + p_chart_uv_bbox(chart, trans, chart->u.pack.size); + + trans[0] = -trans[0]; + trans[1] = -trans[1]; + + p_chart_uv_translate(chart, trans); + + box->w = chart->u.pack.size[0] + trans[0]; + box->h = chart->u.pack.size[1] + trans[1]; + box->index = i; /* warning this index skips PCHART_NOPACK boxes */ + } + + boxPack2D(boxarray, phandle->ncharts-unpacked, &tot_width, &tot_height); + + if (tot_height>tot_width) + scale = 1.0/tot_height; + else + scale = 1.0/tot_height; + + for (i = 0; i < phandle->ncharts-unpacked; i++) { + box = boxarray+i; + trans[0] = box->x; + trans[1] = box->y; + + chart = phandle->charts[box->index]; + p_chart_uv_translate(chart, trans); + p_chart_uv_scale(chart, scale); + } + MEM_freeN(boxarray); } void param_flush(ParamHandle *handle)