707 lines
19 KiB
C
707 lines
19 KiB
C
|
|
/*
|
|||
|
|
* DBcell.c --
|
|||
|
|
*
|
|||
|
|
* Place and Delete subcells
|
|||
|
|
*
|
|||
|
|
* *********************************************************************
|
|||
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|||
|
|
* * Permission to use, copy, modify, and distribute this *
|
|||
|
|
* * software and its documentation for any purpose and without *
|
|||
|
|
* * fee is hereby granted, provided that the above copyright *
|
|||
|
|
* * notice appear in all copies. The University of California *
|
|||
|
|
* * makes no representations about the suitability of this *
|
|||
|
|
* * software for any purpose. It is provided "as is" without *
|
|||
|
|
* * express or implied warranty. Export of this software outside *
|
|||
|
|
* * of the United States of America may require an export license. *
|
|||
|
|
* *********************************************************************
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#ifndef lint
|
|||
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBcell.c,v 1.2 2008/12/11 04:20:04 tim Exp $";
|
|||
|
|
#endif /* not lint */
|
|||
|
|
|
|||
|
|
#include <sys/types.h>
|
|||
|
|
#include <stdio.h>
|
|||
|
|
|
|||
|
|
#include "utils/magic.h"
|
|||
|
|
#include "utils/malloc.h"
|
|||
|
|
#include "utils/geometry.h"
|
|||
|
|
#include "tiles/tile.h"
|
|||
|
|
#include "utils/hash.h"
|
|||
|
|
#include "database/database.h"
|
|||
|
|
#include "database/databaseInt.h"
|
|||
|
|
#include "utils/undo.h"
|
|||
|
|
#include "utils/signals.h"
|
|||
|
|
|
|||
|
|
int placeCellFunc();
|
|||
|
|
int deleteCellFunc();
|
|||
|
|
Tile * clipCellTile();
|
|||
|
|
void dupTileBody();
|
|||
|
|
void cellTileMerge();
|
|||
|
|
bool ctbListMatch();
|
|||
|
|
void freeCTBList();
|
|||
|
|
|
|||
|
|
struct searchArg
|
|||
|
|
{
|
|||
|
|
CellUse * celluse;
|
|||
|
|
Rect * rect;
|
|||
|
|
Plane * plane;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
#define TOPLEFT 10
|
|||
|
|
#define TOPLEFTRIGHT 11
|
|||
|
|
#define TOPBOTTOM 12
|
|||
|
|
#define TOPBOTTOMLEFT 14
|
|||
|
|
#define TOPBOTTOMLEFTRIGHT 15
|
|||
|
|
|
|||
|
|
int dbCellDebug = 0;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*
|
|||
|
|
* DBCellFindDup --
|
|||
|
|
*
|
|||
|
|
* This procedure indicates whether a particular cell is already
|
|||
|
|
* present at a particular point in a particular parent. It is
|
|||
|
|
* used to avoid placing duplicate copies of a cell on top of
|
|||
|
|
* each other.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* The return value is NULL if there is not already a CellUse in parent
|
|||
|
|
* that is identical to use (same bbox and def). If there is a duplicate
|
|||
|
|
* already in parent, then the return value is a pointer to its CellUse.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* None.
|
|||
|
|
*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
CellUse *
|
|||
|
|
DBCellFindDup(use, parent)
|
|||
|
|
CellUse *use; /* Use that is about to be placed in parent.
|
|||
|
|
* Is it a duplicate?
|
|||
|
|
*/
|
|||
|
|
CellDef *parent; /* Parent definiton: does it already have
|
|||
|
|
* something identical to use?
|
|||
|
|
*/
|
|||
|
|
{
|
|||
|
|
Tile *tile;
|
|||
|
|
CellTileBody *body;
|
|||
|
|
CellUse *checkUse;
|
|||
|
|
|
|||
|
|
tile = TiSrPoint((Tile *) NULL, parent->cd_planes[PL_CELL],
|
|||
|
|
&use->cu_bbox.r_ll);
|
|||
|
|
|
|||
|
|
for (body = (CellTileBody *) TiGetBody(tile);
|
|||
|
|
body != NULL;
|
|||
|
|
body = body->ctb_next)
|
|||
|
|
{
|
|||
|
|
checkUse = body->ctb_use;
|
|||
|
|
if (use->cu_def != checkUse->cu_def) continue;
|
|||
|
|
if ((use->cu_bbox.r_xbot != checkUse->cu_bbox.r_xbot)
|
|||
|
|
|| (use->cu_bbox.r_xtop != checkUse->cu_bbox.r_xtop)
|
|||
|
|
|| (use->cu_bbox.r_ybot != checkUse->cu_bbox.r_ybot)
|
|||
|
|
|| (use->cu_bbox.r_ytop != checkUse->cu_bbox.r_ytop))
|
|||
|
|
continue;
|
|||
|
|
return checkUse;
|
|||
|
|
}
|
|||
|
|
return (CellUse *) NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*
|
|||
|
|
* DBPlaceCell --
|
|||
|
|
*
|
|||
|
|
* Add a CellUse to the subcell tile plane of a CellDef.
|
|||
|
|
* Assumes prior check that the new CellUse is not an exact duplicate
|
|||
|
|
* of one already in place.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* None.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Modifies the subcell tile plane of the given CellDef.
|
|||
|
|
* Resets the plowing delta of the CellUse to 0. Sets the
|
|||
|
|
* CellDef's parent pointer to point to the parent def.
|
|||
|
|
*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
DBPlaceCell (celluse, targetcell)
|
|||
|
|
CellUse * celluse; /* new celluse to add to subcell tile plane */
|
|||
|
|
CellDef * targetcell; /* parent cell's definition */
|
|||
|
|
{
|
|||
|
|
Rect rect; /* argument to TiSrArea(), placeCellFunc() */
|
|||
|
|
Plane * plane; /* argument to TiSrArea(), placeCellFunc() */
|
|||
|
|
struct searchArg arg; /* argument to placeCellFunc() */
|
|||
|
|
|
|||
|
|
ASSERT(celluse != (CellUse *) NULL, "DBPlaceCell");
|
|||
|
|
celluse->cu_parent = targetcell;
|
|||
|
|
plane = targetcell->cd_planes[PL_CELL]; /* assign plane */
|
|||
|
|
rect = celluse->cu_bbox;
|
|||
|
|
/* rect = celluse->cu_extended; */
|
|||
|
|
arg.rect = ▭
|
|||
|
|
arg.celluse = celluse;
|
|||
|
|
arg.plane = plane;
|
|||
|
|
|
|||
|
|
/* Be careful not to permit interrupts during this, or the
|
|||
|
|
* database could be left in a trashed state.
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
SigDisableInterrupts();
|
|||
|
|
(void) TiSrArea((Tile *) NULL, plane, &rect, placeCellFunc,
|
|||
|
|
(ClientData) &arg);
|
|||
|
|
targetcell->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
|
|||
|
|
if (UndoIsEnabled())
|
|||
|
|
DBUndoCellUse(celluse, UNDO_CELL_PLACE);
|
|||
|
|
SigEnableInterrupts();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
* DBDeleteCell --
|
|||
|
|
*
|
|||
|
|
* Remove a CellUse from the subcell tile plane of a CellDef.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* None.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Modifies the subcell tile plane of the CellDef, sets the
|
|||
|
|
* parent pointer of the deleted CellUse to NULL.
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
DBDeleteCell (celluse)
|
|||
|
|
CellUse * celluse;
|
|||
|
|
{
|
|||
|
|
Rect rect; /* argument to TiSrArea(), deleteCellFunc() */
|
|||
|
|
Plane * plane; /* argument to TiSrArea(), deleteCellFunc() */
|
|||
|
|
struct searchArg arg; /* argument to deleteCellFunc() */
|
|||
|
|
|
|||
|
|
ASSERT(celluse != (CellUse *) NULL, "DBDeleteCell");
|
|||
|
|
plane = celluse->cu_parent->cd_planes[PL_CELL]; /* assign plane */
|
|||
|
|
rect = celluse->cu_bbox;
|
|||
|
|
arg.rect = ▭
|
|||
|
|
arg.plane = plane;
|
|||
|
|
arg.celluse = celluse;
|
|||
|
|
|
|||
|
|
/* It's important that this code run with interrupts disabled,
|
|||
|
|
* or else we could leave the subcell tile plane in a weird
|
|||
|
|
* state.
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
SigDisableInterrupts();
|
|||
|
|
(void) TiSrArea((Tile *) NULL, plane, &rect, deleteCellFunc,
|
|||
|
|
(ClientData) &arg);
|
|||
|
|
celluse->cu_parent->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
|
|||
|
|
if (UndoIsEnabled())
|
|||
|
|
DBUndoCellUse(celluse, UNDO_CELL_DELETE);
|
|||
|
|
celluse->cu_parent = (CellDef *) NULL;
|
|||
|
|
SigEnableInterrupts();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
* placeCellFunc --
|
|||
|
|
*
|
|||
|
|
* Add a new subcell to a tile.
|
|||
|
|
* Clip the tile with respect to the subcell's bounding box.
|
|||
|
|
* Insert the new CellTileBody into the linked list in ascending order
|
|||
|
|
* based on the celluse pointer.
|
|||
|
|
* This function is passed to TiSrArea.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* 0 is always returned.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Modifies the subcell tile plane of the appropriate CellDef.
|
|||
|
|
* Allocates a new CellTileBody.
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
int
|
|||
|
|
placeCellFunc (tile, arg)
|
|||
|
|
Tile * tile; /* target tile */
|
|||
|
|
struct searchArg * arg; /* celluse, rect, plane */
|
|||
|
|
{
|
|||
|
|
Tile * tp;
|
|||
|
|
CellTileBody * body, * ctp, * ctplast;
|
|||
|
|
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("placeCellFunc called %x\n",tile);
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
tp = clipCellTile (tile, arg->plane, arg->rect);
|
|||
|
|
|
|||
|
|
body = (CellTileBody *) mallocMagic((unsigned) (sizeof (CellTileBody)));
|
|||
|
|
body->ctb_use = arg->celluse;
|
|||
|
|
|
|||
|
|
ctp = (CellTileBody *) tp->ti_body;
|
|||
|
|
ctplast = ctp;
|
|||
|
|
while ((ctp != (CellTileBody *) NULL) && (ctp->ctb_use > body->ctb_use))
|
|||
|
|
{
|
|||
|
|
ctplast = ctp;
|
|||
|
|
ctp = ctp->ctb_next;
|
|||
|
|
}
|
|||
|
|
body->ctb_next = ctp;
|
|||
|
|
|
|||
|
|
if (ctp == (CellTileBody *) tp->ti_body) /* empty list or front of list */
|
|||
|
|
TiSetBody(tp, body);
|
|||
|
|
else /* after at least one CellTileBody */
|
|||
|
|
ctplast->ctb_next = body;
|
|||
|
|
|
|||
|
|
/* merge tiles back into the the plane */
|
|||
|
|
/* requires that TiSrArea visit tiles in NW to SE wavefront */
|
|||
|
|
|
|||
|
|
if ( RIGHT(tp) == arg->rect->r_xtop)
|
|||
|
|
{
|
|||
|
|
if (BOTTOM(tp) == arg->rect->r_ybot)
|
|||
|
|
cellTileMerge (tp, arg->plane, TOPBOTTOMLEFTRIGHT);
|
|||
|
|
else
|
|||
|
|
cellTileMerge (tp, arg->plane, TOPLEFTRIGHT);
|
|||
|
|
}
|
|||
|
|
else if (BOTTOM(tp) == arg->rect->r_ybot)
|
|||
|
|
cellTileMerge (tp, arg->plane, TOPBOTTOMLEFT);
|
|||
|
|
else
|
|||
|
|
cellTileMerge (tp, arg->plane, TOPLEFT);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
* deleteCellFunc --
|
|||
|
|
*
|
|||
|
|
* Remove a subcell from a tile.
|
|||
|
|
* This function is passed to TiSrArea.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* Always returns 0.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Modifies the subcell tile plane of the appropriate CellDef.
|
|||
|
|
* Deallocates a CellTileBody.
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
int
|
|||
|
|
deleteCellFunc (tile, arg)
|
|||
|
|
Tile * tile;
|
|||
|
|
struct searchArg * arg; /* plane, rect */
|
|||
|
|
{
|
|||
|
|
CellTileBody * ctp; /* CellTileBody to be freed */
|
|||
|
|
CellTileBody * ctplast; /* follows one behind ctp */
|
|||
|
|
CellUse * celluse;
|
|||
|
|
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("deleteCellFunc called %x\n",tile);
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
celluse = arg->celluse;
|
|||
|
|
|
|||
|
|
/* find the appropriate CellTileBody in the linked list */
|
|||
|
|
|
|||
|
|
ctp = (CellTileBody *) tile->ti_body;
|
|||
|
|
ctplast = ctp;
|
|||
|
|
while ((ctp != (CellTileBody *) NULL) && (ctp->ctb_use != celluse))
|
|||
|
|
{
|
|||
|
|
ctplast = ctp;
|
|||
|
|
ctp = ctp->ctb_next;
|
|||
|
|
}
|
|||
|
|
/* there should have been a match */
|
|||
|
|
if (ctp == (CellTileBody *) NULL)
|
|||
|
|
{
|
|||
|
|
ASSERT (ctp != (CellTileBody *) NULL, "deleteCellFunc");
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/* relink the list with one CellTileBody deleted */
|
|||
|
|
if (ctp == ctplast) /* front of list */
|
|||
|
|
TiSetBody(tile, ctp->ctb_next);
|
|||
|
|
else /* beyond front of list */
|
|||
|
|
ctplast->ctb_next = ctp->ctb_next;
|
|||
|
|
|
|||
|
|
freeMagic((char *) ctp);
|
|||
|
|
|
|||
|
|
/* merge tiles back into the the plane */
|
|||
|
|
/* requires that TiSrArea visit tiles in NW to SE wavefront */
|
|||
|
|
|
|||
|
|
if ( RIGHT(tile) == arg->rect->r_xtop)
|
|||
|
|
{
|
|||
|
|
if (BOTTOM(tile) == arg->rect->r_ybot)
|
|||
|
|
cellTileMerge (tile, arg->plane, TOPBOTTOMLEFTRIGHT);
|
|||
|
|
else
|
|||
|
|
cellTileMerge (tile, arg->plane, TOPLEFTRIGHT);
|
|||
|
|
}
|
|||
|
|
else if (BOTTOM(tile) == arg->rect->r_ybot)
|
|||
|
|
cellTileMerge (tile, arg->plane, TOPBOTTOMLEFT);
|
|||
|
|
else
|
|||
|
|
cellTileMerge (tile, arg->plane, TOPLEFT);
|
|||
|
|
return (0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
* clipCellTile --
|
|||
|
|
*
|
|||
|
|
* Clip the given tile against the given rectangle.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* Returns a pointer to the clipped tile.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Modifies the database plane that contains the given tile.
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
Tile *
|
|||
|
|
clipCellTile (tile, plane, rect)
|
|||
|
|
Tile * tile;
|
|||
|
|
Plane * plane;
|
|||
|
|
Rect * rect;
|
|||
|
|
{
|
|||
|
|
Tile * newtile;
|
|||
|
|
|
|||
|
|
if (TOP(tile) > rect->r_ytop)
|
|||
|
|
{
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitY TOP\n");
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
newtile = TiSplitY (tile, rect->r_ytop); /* no merge */
|
|||
|
|
dupTileBody (tile, newtile);
|
|||
|
|
}
|
|||
|
|
if (BOTTOM(tile) < rect->r_ybot)
|
|||
|
|
{
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitY BOTTOM\n");
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
newtile = tile;
|
|||
|
|
tile = TiSplitY (tile, rect->r_ybot); /* no merge */
|
|||
|
|
dupTileBody (newtile, tile);
|
|||
|
|
}
|
|||
|
|
if (RIGHT(tile) > rect->r_xtop)
|
|||
|
|
{
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitX RIGHT\n");
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
newtile = TiSplitX (tile, rect->r_xtop);
|
|||
|
|
dupTileBody (tile, newtile);
|
|||
|
|
cellTileMerge (newtile, plane, TOPBOTTOM);
|
|||
|
|
}
|
|||
|
|
if (LEFT(tile) < rect->r_xbot)
|
|||
|
|
{
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitX LEFT\n");
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
newtile = tile;
|
|||
|
|
tile = TiSplitX (tile, rect->r_xbot);
|
|||
|
|
dupTileBody (newtile, tile);
|
|||
|
|
cellTileMerge (newtile, plane, TOPBOTTOM);
|
|||
|
|
}
|
|||
|
|
return (tile);
|
|||
|
|
} /* clipCellTile */
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
* dupTileBody --
|
|||
|
|
*
|
|||
|
|
* Duplicate the body of an old tile as the body for a new tile.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* None.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Allocates new CellTileBodies unless the old tile was a space tile.
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
dupTileBody (oldtp, newtp)
|
|||
|
|
Tile * oldtp;
|
|||
|
|
Tile * newtp;
|
|||
|
|
{
|
|||
|
|
CellTileBody * oldctb, * newctb, * newctblast;
|
|||
|
|
|
|||
|
|
oldctb = (CellTileBody *) oldtp->ti_body;
|
|||
|
|
if (oldctb != (CellTileBody *) NULL)
|
|||
|
|
{
|
|||
|
|
newctb = (CellTileBody *) mallocMagic((unsigned) (sizeof (CellTileBody)));
|
|||
|
|
TiSetBody(newtp, newctb);
|
|||
|
|
newctb->ctb_use = oldctb->ctb_use;
|
|||
|
|
|
|||
|
|
oldctb = oldctb->ctb_next;
|
|||
|
|
newctblast = newctb;
|
|||
|
|
|
|||
|
|
while (oldctb != (CellTileBody *) NULL)
|
|||
|
|
{
|
|||
|
|
newctb = (CellTileBody *) mallocMagic((unsigned) (sizeof (CellTileBody)));
|
|||
|
|
newctblast->ctb_next = newctb;
|
|||
|
|
newctb->ctb_use = oldctb->ctb_use;
|
|||
|
|
|
|||
|
|
oldctb = oldctb->ctb_next;
|
|||
|
|
newctblast = newctb;
|
|||
|
|
}
|
|||
|
|
newctblast->ctb_next = (CellTileBody *) NULL;
|
|||
|
|
}
|
|||
|
|
else TiSetBody(newtp, NULL);
|
|||
|
|
} /* dupTileBody */
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
* cellTileMerge --
|
|||
|
|
*
|
|||
|
|
* Merge the given tile with its plane in the directions specified.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* None.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Modifies the database plane that contains the given tile.
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
cellTileMerge (tile, plane, direction)
|
|||
|
|
Tile * tile;
|
|||
|
|
Plane * plane;
|
|||
|
|
int direction; /* TOP = 8, BOTTOM = 4, LEFT = 2, RIGHT = 1 */
|
|||
|
|
{
|
|||
|
|
Point topleft, bottomright;
|
|||
|
|
Tile * dummy, * tpleft, * tpright, * tp1, * tp2;
|
|||
|
|
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("cellTileMerge %x\n",tile);
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
topleft.p_x = LEFT(tile);
|
|||
|
|
topleft.p_y = TOP(tile);
|
|||
|
|
bottomright.p_x = RIGHT(tile);
|
|||
|
|
bottomright.p_y = BOTTOM(tile);
|
|||
|
|
|
|||
|
|
if ((direction >> 1) % 2) /* LEFT */
|
|||
|
|
{
|
|||
|
|
tpright = tile;
|
|||
|
|
tpleft = BL(tpright);
|
|||
|
|
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("LEFT %x %x\n",tpleft,tpright);
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
while (BOTTOM(tpleft) < topleft.p_y) /* go up left edge */
|
|||
|
|
{
|
|||
|
|
if (ctbListMatch (tpleft, tpright))
|
|||
|
|
{
|
|||
|
|
if (BOTTOM(tpleft) < BOTTOM(tpright))
|
|||
|
|
{
|
|||
|
|
dummy = tpleft;
|
|||
|
|
tpleft = TiSplitY (tpleft, BOTTOM (tpright));
|
|||
|
|
dupTileBody (dummy, tpleft);
|
|||
|
|
}
|
|||
|
|
else if (BOTTOM(tpleft) > BOTTOM(tpright))
|
|||
|
|
{
|
|||
|
|
dummy = tpright;
|
|||
|
|
tpright = TiSplitY (tpright, BOTTOM (tpleft));
|
|||
|
|
dupTileBody (dummy, tpright);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (TOP(tpleft) > TOP(tpright))
|
|||
|
|
{
|
|||
|
|
dummy = TiSplitY (tpleft, TOP(tpright));
|
|||
|
|
dupTileBody (tpleft, dummy);
|
|||
|
|
}
|
|||
|
|
else if (TOP(tpright) > TOP(tpleft))
|
|||
|
|
{
|
|||
|
|
dummy = TiSplitY (tpright, TOP(tpleft));
|
|||
|
|
dupTileBody (tpright, dummy);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
freeCTBList (tpright);
|
|||
|
|
TiJoinX (tpleft, tpright, plane); /* tpright disappears */
|
|||
|
|
|
|||
|
|
tpright = RT(tpleft);
|
|||
|
|
if (BOTTOM(tpright) < topleft.p_y) tpleft = BL(tpright);
|
|||
|
|
else tpleft = tpright; /* we're off the top of the tile */
|
|||
|
|
/* this will break the while loop */
|
|||
|
|
} /* if (ctbListMatch (tpleft, tpright)) */
|
|||
|
|
|
|||
|
|
else tpleft = RT(tpleft);
|
|||
|
|
} /* while */
|
|||
|
|
tile = tpleft; /* for TiSrPoint in next IF statement */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (direction % 2) /* RIGHT */
|
|||
|
|
{
|
|||
|
|
tpright = TiSrPoint (tile, plane, &bottomright);
|
|||
|
|
--(bottomright.p_x);
|
|||
|
|
tpleft = TiSrPoint (tpright, plane, &bottomright);
|
|||
|
|
++(bottomright.p_x);
|
|||
|
|
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("RIGHT %x %x\n",tpleft,tpright);
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
while (BOTTOM(tpright) < topleft.p_y) /* go up right edge */
|
|||
|
|
{
|
|||
|
|
if (ctbListMatch (tpleft, tpright))
|
|||
|
|
{
|
|||
|
|
if (BOTTOM(tpright) < BOTTOM(tpleft))
|
|||
|
|
{
|
|||
|
|
dummy = tpright;
|
|||
|
|
tpright = TiSplitY (tpright, BOTTOM(tpleft));
|
|||
|
|
dupTileBody (dummy, tpright);
|
|||
|
|
}
|
|||
|
|
else if (BOTTOM(tpleft) < BOTTOM(tpright))
|
|||
|
|
{
|
|||
|
|
dummy = tpleft;
|
|||
|
|
tpleft = TiSplitY (tpleft, BOTTOM(tpright));
|
|||
|
|
dupTileBody (dummy, tpleft);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (TOP(tpright) > TOP(tpleft))
|
|||
|
|
{
|
|||
|
|
dummy = TiSplitY (tpright, TOP(tpleft));
|
|||
|
|
dupTileBody (tpright, dummy);
|
|||
|
|
}
|
|||
|
|
else if (TOP(tpleft) > TOP(tpright))
|
|||
|
|
{
|
|||
|
|
dummy = TiSplitY (tpleft, TOP(tpright));
|
|||
|
|
dupTileBody (tpleft, dummy);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
freeCTBList (tpright);
|
|||
|
|
TiJoinX (tpleft, tpright, plane); /* tpright disappears */
|
|||
|
|
|
|||
|
|
tpright = RT(tpleft);
|
|||
|
|
while (LEFT(tpright) > bottomright.p_x) tpright = BL(tpright);
|
|||
|
|
|
|||
|
|
/* tpleft can be garbage if we're off the top of the loop, */
|
|||
|
|
/* but it doesn't matter since the expression tests tpright */
|
|||
|
|
|
|||
|
|
tpleft = BL(tpright);
|
|||
|
|
} /* if (ctbListMatch (tpleft, tpright)) */
|
|||
|
|
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
tpright = RT(tpright);
|
|||
|
|
while (LEFT(tpright) > bottomright.p_x) tpright = BL(tpright);
|
|||
|
|
tpleft = BL(tpright); /* left side merges may have */
|
|||
|
|
/* created more tiles */
|
|||
|
|
}
|
|||
|
|
} /* while */
|
|||
|
|
tile = tpright; /* for TiSrPoint in next IF statement */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ((direction >> 3) % 2) /* TOP */
|
|||
|
|
{
|
|||
|
|
tp1 = TiSrPoint (tile, plane, &topleft); /* merge across top */
|
|||
|
|
|
|||
|
|
--(topleft.p_y);
|
|||
|
|
tp2 = TiSrPoint (tile, plane, &topleft);/* top slice of original tile */
|
|||
|
|
++(topleft.p_y);
|
|||
|
|
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("TOP %x %x\n",tp1,tp2);
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
if ((LEFT(tp1) == LEFT(tp2) ) &&
|
|||
|
|
(RIGHT(tp1) == RIGHT(tp2)) &&
|
|||
|
|
(ctbListMatch (tp1, tp2) ))
|
|||
|
|
{
|
|||
|
|
freeCTBList (tp2);
|
|||
|
|
TiJoinY (tp1, tp2, plane);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tile = tp1; /* for TiSrPoint in next IF statement */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ((direction >> 2) % 2) /* BOTTOM */
|
|||
|
|
{
|
|||
|
|
--(bottomright.p_x);
|
|||
|
|
/* bottom slice of orig tile */
|
|||
|
|
tp1 = TiSrPoint (tile, plane, &bottomright);
|
|||
|
|
|
|||
|
|
--(bottomright.p_y);
|
|||
|
|
tp2 = TiSrPoint (tile, plane, &bottomright); /* merge across bottom */
|
|||
|
|
|
|||
|
|
#ifdef CELLDEBUG
|
|||
|
|
if (dbCellDebug) TxPrintf("BOTTOM %x %x\n",tp1,tp2);
|
|||
|
|
#endif /* CELLDEBUG */
|
|||
|
|
|
|||
|
|
if ((LEFT(tp1) == LEFT(tp2) ) &&
|
|||
|
|
(RIGHT(tp1) == RIGHT(tp2)) &&
|
|||
|
|
(ctbListMatch (tp1, tp2) ))
|
|||
|
|
{
|
|||
|
|
freeCTBList (tp2);
|
|||
|
|
TiJoinY (tp1, tp2, plane);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
* freeCTBList --
|
|||
|
|
*
|
|||
|
|
* Free all CellTileBodies attached to the give tile.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* None.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Frees CellTileBodies.
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
freeCTBList (tile)
|
|||
|
|
Tile * tile;
|
|||
|
|
{
|
|||
|
|
CellTileBody * ctp, * ctplast;
|
|||
|
|
|
|||
|
|
ctp = (CellTileBody *) tile->ti_body;
|
|||
|
|
while (ctp != (CellTileBody *) NULL)
|
|||
|
|
{
|
|||
|
|
ctplast = ctp;
|
|||
|
|
ctp = ctp->ctb_next;
|
|||
|
|
freeMagic((char *) ctplast);
|
|||
|
|
}
|
|||
|
|
TiSetBody(tile, NULL);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
* ctbListMatch --
|
|||
|
|
*
|
|||
|
|
* Compare two linked lists of CellTileBodies, assuming that they are
|
|||
|
|
* sorted in ascending order by celluse pointers.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* True if the tiles have identical lists of CellTileBodies.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* None.
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
bool
|
|||
|
|
ctbListMatch (tp1, tp2)
|
|||
|
|
Tile * tp1, * tp2;
|
|||
|
|
{
|
|||
|
|
CellTileBody * ctp1, * ctp2;
|
|||
|
|
|
|||
|
|
ctp1 = (CellTileBody *) tp1->ti_body;
|
|||
|
|
ctp2 = (CellTileBody *) tp2->ti_body;
|
|||
|
|
while (ctp1 && ctp2 && (ctp1->ctb_use == ctp2->ctb_use))
|
|||
|
|
ctp1 = ctp1->ctb_next, ctp2 = ctp2->ctb_next;
|
|||
|
|
|
|||
|
|
return ((ctp1 == (CellTileBody *) NULL) && (ctp2 == (CellTileBody *) NULL));
|
|||
|
|
}
|