[java] More of the ImageProducer

Started by
15 comments, last by Jim_Ross 24 years, 2 months ago
You could use two loops like this:

int[][] theBigImage;
int[][] myTileImage;
int tileImageWidth = myTileImage.length;
int tileImageHeight = myTileImage[0].length;
int xOffset = 32; // The X coordinate of the tile
int yOffset = 32; // The Y coordinate of the tile

for ( int y = 0; y < tileImageHeight; y++ )
{
for ( int x = 0; x < tileImageWidth; x++ )
{
try
{
theBigImage[x+xOffset][y+yOffset] =
myTileImage[x][y];
}
catch( ArrayIndexOutOfBoundsException clipping )
{
// We are trying to draw outside the big image
// which means clipping, just ignore the exception
}
}
}

This is quite ineffecient ( the inner loop should be replaced with System.arraycopy() ), copying should be stopped if the y+yOffset becomes bigger than theBigImage''s height etc. But basically I believe this is the idea...

Also alpha blitting (leaving some parts of theBigImage untouched) requires something more complicated, but someone else with more experience could enlighten us on this
-Pasi Keranen
Advertisement
Yep, you should definately use arraycopy() for each line if you are doing a regular image copy (WHY, OH WHY, didn''t they implement an arraycopy() that takes a pitch parameter ...) And no, exceptions are not a replacement of goold old fashioned clipping !!

If you need to do alpha blending, you can''t use arraycopy since obviously you need to modify each pixel.

The general formula is d = d*(1-a) + s*a (Where d is destination pixel, s is source pixel and a is transparency (between 0 and 1)). A few tricks:

1) Premultiply the source and invert the alpha channel to reduce the expression to d = d*a + s ...

2) Skip pixels that are >95% transparent and do a raw copy of pixels that are <5% transparent. (The penalty of the check is worth it for most applications since the majority of the image is usually either opaque or transparent)

3) Use integer math (Yes, floating point is MUCH faster than it used to be, but integers are still faster)

4) Don''t underestimate the power of basic bit manipulation functions (and, shift, xor etc.) You can skip a lot of code by doing things in the right order.

/Niels
<b>/NJ</b>
A-hah, so the bigImage is a 2D array. and you use offest to get the placement right. Instead of a 2D array of tile images, how''sabout a MapTile class that has a 2D array as a member variable, instead of an Image variable. then you could do System.arrayCopy() on thisMapTile.tileImage[][], which would be an array of pixels. That''s what i''m shootin fer now, tell me if there''s something horribly wrong with it. I have all the map tiles in a huge List object, and i just grab subList()s in the drawing routine to only draw the visible arrea. That seems to work fine as it is, but the MapTiles have Image variables and that''s what i need to get rid of i guess.

Thanks of all the code examples and alpha blending stuff.

Let''s see if we can''t get more posts than the linux group
Actually, the big image is a 1D array - it''s just an array of width*height integers. Copying a (w x h) block, pixel by pixel from source (srcx,srcy) to destination (destx,desty), is nothing more complicated than this:

int dest[destwidth*destheight];
int src[srcwidth*srcheight];

for(y=0;y{
for(x=0;x {
dest[ destx + x + (desty+y)*destwidth ] =
src [ srcx + x + (srcy+y)*srcwidth ];
}
}

Obviously you shouldn''t do multiplications inside the inner loop + use arraycopy() as mentioned previously... But that is the idea in all its simplicity.

What you are suggesting with arraycopy won''t work because even though your source image would be one long stream of pixels, your destination image is not.

/Niels
<b>/NJ</b>
Sorry, don''t get it. Now i''m more confused.
Maybe I could help a bit. Lest modify Niel''s example a bit:

int bigImage[screenWidth*screenHeight];
int tileImage[tileWidth*tileHeight];
int srcRowOffset, dstRowOffset;

// Copy a tile to coordinates x,y in the big image
for( row = 0; row < tileHeight; row++ )
{
// Precalculate the offset for a row
srcRowOffset = (y + row) * tileWidth;
dstRowOffset = (y + row) * dstWidth;
for( col = 0; col < tileWidth; col++ )
{
bigImage[ x + col + dstRowOffset ] =
tileImage [ x + col + srcRowOffset ];
}
}

And you could replace the inner loop (the loop that goes through the columns with a System.arraycopy() call) to optimize a bit more. This as you can see copies a rectangular are the size of tileWidth*tileHeight to the big image. To allow making a "keycolor transparent blit" (leaving some of the pixels in the bigImage untouched by your tileImage) you could add to the inner loop an if-clause:

int srcPixel = tileImage [ x + col + srcRowOffset ];
if ( srcPixel != transparentKeyColor )
{
bigImage[ x + col + dstRowOffset ] = srcPixel;
}

Where the transparentKeyColor should be some defined colour, like if you want the upper left of the tileImage define the transparent key color you can do just (in the beginning of the draw method:

int transparentKeyColor = tileImage[ 0 ];

Does this help, or does it confuse even more?
-Pasi Keranen
Whoops, sorry about the code sample - forgot about the greater-than symbol being interpreted as an HTML tag !...
<b>/NJ</b>

This topic is closed to new replies.

Advertisement