Is the only reason you copy the pixels to a temporary buffer to do clipping? You set the pixels to transparent to prevent them from from appearing on the other side of the screen? You can probably just copy straight to the framebuffer. For the parts that need clipping, adjust the source, destination, and length of the copies.
For left edge clipping, you always have the destination start be the left edge of the screen. You need to figure out how much of the tile is hanging off the left edge; this is the negative X of the left edge of the tile. Then add that as an offset to the start of the source to shift over where it gets its pixels from, and subtract the same amount from the length of the copy. You can simplify out the negation of the X position and just reverse the adds and subtracts.
For right edge clipping, just subtract the number of off screen pixels from the length. The number of off screen pixels is (Screen width - X + Tile width). Since screen and tile width don't change, you can combine them into a right clipping edge value and do (Right clipping edge - X). Source and destination are as normal.
Here's and example left and right edge X clipper in C. It draws one row of pixels, passed in with tilestart, at a given X and Y. X has to be even (word aligned) or the copy functions will do unaligned accesses, and at least part of the tile has to be on screen; don't call the function at all if the tile is completely off screen.
Code: Select all
#define tilewidth (16) /* tile width in pixels */
#define fbwidth (320) /* framebuffer width in pixels */
#define fbheight (224) /* framebuffer height in pixels */
#define fbrightclip (fbwidth - tilewidth) /* right side clipping edge in pixels */
#define framebuffer ((short*)XXXXXXX) /* pointer to framebuffer */
void draw_tile_row(int fbx, int fby, short *tilerowstart)
{
char *linestart = (char*)framebuffer + fby*fbwidth;
if (fbx < 0) {
// Left edge of tile goes off the left edge of the screen
fast_wmemcpy((short*)linestart, (short*)((char*)tilerowstart - fbx), tilewidth + fbx);
} else if (fbx > fbrightclip) {
// Right edge of tile goes off the right edge of the screen.
int wordsoffscreen = fbrightclip - fbx;
fast_wmemcpy((short*)(linestart + fbx), tilerowstart, tilewidth - wordsoffscreen);
} else {
// Tile is completely on screen
word_8byte_copy((short*)(linestart + fbx), tilerowstart, tilewidth/8);
}
}
I haven't tried compiling it or anything, so I don't know if it works right; but I think it should show the general idea.
You'll also want to have the clipping detection outside of the innermost loops, rather than doing it for every tile. You can cut down on the majority of checks by processing your tile map like this:
Code: Select all
draw top row with clipping
draw bottom row with clipping
for each row not touching the top and bottom edges {
draw left edge tile with clipping
fast block draw middle unclipped tiles
draw right edge tile with clipping
}
If you really need to get the most speed possible, you can write special versions of the clipping code for each edge and corner of the screen, to minimize the number of conditionals. You can process all possible clipping conditions for the entire screen in two checks, instead of doing multiple checks per tile, and reuse clipping calculations with multiple tiles, at the cost of greatly complicating the code. Don't bother with this method unless the above isn't fast enough. Here's what it would look like, though:
Code: Select all
if left and right edges need clipping {
if top and bottom rows need clipping {
draw top left tile with top left clipping
draw top right tile with top right clipping
fast block draw top tiles with top clipping
draw bottom left tile with bottom left clipping
draw bottom right tile with bottom right clipping
fast block draw bottom tiles with bottom clipping
}
for each row without y clipping {
draw left edge tile with left clipping
fast block draw middle unclipped tiles
draw right edge tile with right clipping
}
} else {
if top and bottom rows need clipping {
fast block draw top tiles with top clipping
fast block draw bottom tiles with bottom clipping
}
for each row without y clipping {
fast block draw middle unclipped tiles
}
}
Here's a single word reverse pixel copy routine for clipping flipped tiles, since one hasn't been posted yet.
Code: Select all
.align 4
.global _fast_wmemcpy_bytereverse
_fast_wmemcpy_bytereverse:
add r6,r4
add r6,r4 !dst = dst + count * 2
1: mov.w @r5+,r3
dt r6
swap.b r3,r3
bf/s 1b
mov.w r3,@-r4
rts
nop
Actually, it might be possible to go without clipping if the line table format is flexible enough to let you use a 336 by 240 pixel frame buffer and use the line table and screen shift to adjust a 320 by 224 window. If each word in the line table is converted into a pointer into the frame buffer RAM by a left shift, it should be no problem to do so, but with the docs I have I can't figure out if it's really possible.