legacy-imlib2/updates.c

211 lines
4.1 KiB
C

#include "common.h"
#include "updates.h"
enum _t_used
{
T_UNUSED = 0,
T_USED = 1
};
struct _tile
{
enum _t_used used;
};
#define TBITS 5
#define TB TBITS
#define TM ((1 << TBITS) - 1)
#define TS (1 << TBITS)
#define T(x, y) t[((y) * tw) + (x)]
#define CLIP(x, y, w, h, xx, yy, ww, hh) \
if (x < xx) {w += x; x = xx;} \
if (y < yy) {h += y; y = yy;} \
if ((x + w) > ww) {w = ww - x;} \
if ((y + h) > hh) {h = hh - y;}
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
ImlibUpdate *
__imlib_MergeUpdate(ImlibUpdate *u, int w, int h, int hgapmax)
{
ImlibUpdate *nu = NULL, *uu;
struct _tile *t;
int tw, th, x, y, i;
int *gaps = NULL;
/* if theres no rects to process.. return NULL */
if (!u)
return NULL;
/* if theres only one rect - return it - no point cleaning up 1 rect */
if (!u->next)
return u;
tw = w >> TB;
if (w & TM)
tw++;
th = h >> TB;
if (h & TM)
th++;
t = malloc(tw * th * sizeof(struct _tile));
/* fill in tiles to be all not used */
for (i = 0, y = 0; y < th; y++)
{
for (x = 0; x < tw; x++)
t[i++].used = T_UNUSED;
}
/* fill in all tiles*/
for (uu = u; uu; uu = uu->next)
{
CLIP(uu->x, uu->y, uu->w, uu->h, 0, 0, w, h);
for (y = uu->y >> TB; y <= ((uu->y + uu->h - 1) >> TB); y++)
{
for (x = uu->x >> TB; x <= ((uu->x + uu->w - 1) >> TB); x++)
T(x, y).used = T_USED;
}
}
/* scan each line - if > hgapmax gaps between tiles, then fill smallest */
gaps = malloc(tw *sizeof(int));
for (y = 0; y < th; y++)
{
int hgaps = 0, start = -1, min;
char have = 1, gap = 0;
for (x = 0; x < tw; x++)
gaps[x] = 0;
for (x = 0; x < tw; x++)
{
if ((have) && (T(x, y).used == T_UNUSED))
{
start = x;
gap = 1;
have = 0;
}
else if ((!have) && (gap) && (T(x, y).used & T_USED))
{
gap = 0;
hgaps++;
have = 1;
gaps[start] = x - start;
}
else if (T(x, y).used & T_USED)
have = 1;
}
while (hgaps > hgapmax)
{
start = -1;
min = tw;
for (x = 0; x < tw; x++)
{
if ((gaps[x] > 0) && (gaps[x] < min))
{
start = x;
min = gaps[x];
}
}
if (start >= 0)
{
gaps[start] = 0;
for (x = start;
T(x, y).used == T_UNUSED;
T(x++, y).used = T_USED);
hgaps--;
}
}
}
free(gaps);
/* coalesce tiles into larger blocks and make new rect list */
for (y = 0; y < th; y++)
{
for (x = 0; x < tw; x++)
{
if (T(x, y).used & T_USED)
{
int xx, yy, ww, hh, ok;
for (xx = x + 1, ww = 1;
(T(xx, y).used & T_USED) && (xx < tw);
xx++, ww++);
for (yy = y + 1, hh = 1, ok = 1;
(yy < th) && (ok);
yy++, hh++)
{
for (xx = x; xx < (x + ww); xx++)
{
if (!(T(xx, yy).used & T_USED))
{
ok = 0;
xx = x + ww;
hh--;
}
}
}
for (yy = y; yy < (y + hh); yy++)
{
for (xx = x; xx < (x + ww); xx++)
T(xx, yy).used = T_UNUSED;
}
nu = __imlib_AddUpdate(nu, (x << TB), (y << TB),
(ww << TB), (hh << TB));
}
}
}
free(t);
__imlib_FreeUpdates(u);
return nu;
}
ImlibUpdate *
__imlib_AddUpdate(ImlibUpdate *u, int x, int y, int w, int h)
{
ImlibUpdate *nu;
if ((w < 1) || (h < 1) || ((x + w) < 1) || ((y + h) < 1))
return u;
nu = malloc(sizeof(ImlibUpdate));
nu->x = x;
nu->y = y;
nu->w = w;
nu->h = h;
nu->next = u;
return nu;
}
void
__imlib_FreeUpdates(ImlibUpdate *u)
{
ImlibUpdate *uu;
uu = u;
while (uu)
{
u = uu;
uu = uu->next;
free(u);
}
}
ImlibUpdate *
__imlib_DupUpdates(ImlibUpdate *u)
{
ImlibUpdate *uu, *cu, *pu, *ru;
if (!u)
return NULL;
uu = malloc(sizeof(ImlibUpdate));
memcpy(uu, u, sizeof(ImlibUpdate));
cu = u->next;
pu = u;
ru = uu;
while (cu)
{
uu = malloc(sizeof(ImlibUpdate));
memcpy(uu, u, sizeof(ImlibUpdate));
pu->next = uu;
pu = cu;
cu = cu->next;
}
return ru;
}