Jump to content

  • Log In with Google      Sign In   
  • Create Account


[java] More of the ImageProducer


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
16 replies to this topic

#1 Jim_Ross   Members   -  Reputation: 122

Like
Likes
Like

Posted 22 January 2000 - 09:33 AM

Let's see here... I was using straight 32x32 images for the sprites and background of this game on which i'm working. Then i decided to use a tileset image instead. So i went through and gave offset numbers to objects that previously had images. Then, in the drawing routine, i set a clipping region, moved the tileset image to the correct offset, then painted it. The problem is, it is a hell of a lot slower than using individual images. I don't want to keep using individual images outside of the game. Does anyone think using the ImageProducer/Consumer model to extract Image objects from the tileset image (one time only) would be a good idea? Would it be almost as fast as using individual images? Edited by - Jim_Ross on 1/22/00 6:49:43 PM

Sponsor:

#2 javanerd   Members   -  Reputation: 122

Like
Likes
Like

Posted 23 January 2000 - 12:59 AM

You could use the PixelGrabber to do the slicing and dicing of the tileset image and you''d get individual Image objects. This is as fast as loading individual images, but the downside is increased memory usage over one large image. So basically you have a choice between using lots of memory or having lot less speed.

#3 Jim_Ross   Members   -  Reputation: 122

Like
Likes
Like

Posted 23 January 2000 - 06:40 AM

Any idea why that technique is so slow? Is that the technique you use in your gameframe?

#4 Niels   Members   -  Reputation: 122

Like
Likes
Like

Posted 23 January 2000 - 09:52 AM

All the game graphics at www.hexadome.net is chopped from a large bitmap and alpha blended into the background run-time. I do all image manipulation in an integer array, convert it to an Image using the MemoryImageSource and then blit it to the screen...

(The map is drawn into the integer array first, pixel by pixel (alphablended), using splines to determine blending degree between the various textures)...

/Niels

#5 Jim_Ross   Members   -  Reputation: 122

Like
Likes
Like

Posted 23 January 2000 - 05:36 PM

Not too sure what ''blitting'' is exactly. So you break apart the image into pixel array data. Then associate that raw pixel data with a tile instead of a java Image object, then you combine all of those arrays into one large array. Send it to ImageProducer and then something like g.drawImage(WhatIGotfromImageProcucer,0,0,null) ...?
If that''s not what you do, would that be an okay thing to do? It seems like you would have to take the tiled 32x32 (or whatever) pixel array and turn it back into an Image to associate it with the Tile object. How else could you keep the lines staright when creating the large, entire map, array? Like print the first row of pixel data from tile 1,2,3... then the second row of pixel data form tile 1,2,3... and so on?

#6 javanerd   Members   -  Reputation: 122

Like
Likes
Like

Posted 23 January 2000 - 07:25 PM

The speed decrease comes from using the clipregions, more specifically when you set a clip region in a graphics context you are changing the state of the graphics context and that is allways slow. When you have to do that changing each time you blit (draw) an image to the screen it is bound to have a negative impact on the speed.

#7 javanerd   Members   -  Reputation: 122

Like
Likes
Like

Posted 23 January 2000 - 07:30 PM

The image producer thingie sounds very interesting as it would allow many fancy effects. I''ve known for a while that Java demos use this technique and that is understandable as most of the cool demo effects are based on wiggling the bits of an image. But is this technique really faster than using plain images and drawImage() method of the graphics object? Or is the main benefit the flexibility (ability to do alpha blits and other stuff)?

#8 Jim_Ross   Members   -  Reputation: 122

Like
Likes
Like

Posted 24 January 2000 - 02:59 AM

I don''t know if it''s faster, but if it''s the only way to use large (actually only about 192x192) tileset images instead of hundreds of individual images then it''s gotta be the way to go.

#9 Niels   Members   -  Reputation: 122

Like
Likes
Like

Posted 24 January 2000 - 09:22 PM

Doh! What happened to the post I made yesterday?

Anyway what I said was that while it is obviously not faster for raw copying of a single image (presumably, drawImage use the HW blitter if present, or at least a very fast memcpy() implemented in assembler or the like), it has certain advantages when doing a lot of pixel-level manipulation.

When manipulating the image you essentially set integers in an array which is substantially faster than using get/setPixel() on an image. The overhead comes from converting the integer array into an image for display (And this is surprisingly fast).

/Niels

#10 Jim_Ross   Members   -  Reputation: 122

Like
Likes
Like

Posted 25 January 2000 - 12:57 PM

so, you''re entire bg is one large array of data representing the pixels, then you make an image from that data and draw it to the screen. But how do you make that large array of data from the smaller arrays of data (the tiles). What i''m saying is, if i just copy the individual tile array to the larger map array, the tiles will just be long strands of images, not squares of images.... ya know?

#11 javanerd   Members   -  Reputation: 122

Like
Likes
Like

Posted 25 January 2000 - 08:51 PM

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

#12 Niels   Members   -  Reputation: 122

Like
Likes
Like

Posted 26 January 2000 - 02:22 AM

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

#13 Jim_Ross   Members   -  Reputation: 122

Like
Likes
Like

Posted 26 January 2000 - 04:48 AM

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

#14 Niels   Members   -  Reputation: 122

Like
Likes
Like

Posted 28 January 2000 - 01:10 AM

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

#15 Jim_Ross   Members   -  Reputation: 122

Like
Likes
Like

Posted 29 January 2000 - 05:58 AM

Sorry, don''t get it. Now i''m more confused.

#16 javanerd   Members   -  Reputation: 122

Like
Likes
Like

Posted 29 January 2000 - 11:47 PM

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?

#17 Niels   Members   -  Reputation: 122

Like
Likes
Like

Posted 31 January 2000 - 02:09 AM

Whoops, sorry about the code sample - forgot about the greater-than symbol being interpreted as an HTML tag !...




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS