yes - the alpha channel of the GIF
if you edit with Photoshop or GIMP or whatever, the "transparency" (usually represented by a grid) becomes the alpha channel.
or, you could transparentize it in code (uncompiled):
protected BufferedImage trans(BufferedImage src,Color alpha) {
BufferedImage b = new BufferedImage(src.getWidth(),src.getHeight(),BufferedImage.TYPE_INT_ARGB);
int x,y,rgb;
for (y = 0;y < b.getHeight();y++) {
for (x = 0;x < b.getWidth();x++) {
rgb = src.getRGB(x,y);
if (rgb == alpha.getRGB()) {
b.setRGB(x,y,0x00000000);
}
else b.setRGB(x,y,src.getRGB(x,y));
}
}
return b;
}
Transparency should render just fine. Have you checked the image by loading it in an editor? Is there anything you're rendering the image on which is rendering the black itself? If you're painting directly to a Graphics object, where did you obtain that object from?
In any case why not join the 21st century and use PNGs ;o)
PNGs are smaller than .gif right?
PNGs are different to GIFs. You can do more and different things with them. You can store more complex data. For example you can have true-color images and alpha channels instead of palletised transparency masking, set gamma values, etc.
Size depends on lots of things.
Is it possible to look at the hex value of the color?
Which color? You can pull pixels out of images to check them, you must be able to pull them out of the palette as well although I forget how - no doubt some route via IIOMetadata will give you what you want.
Is it stupid having a image loaded that is 4000 x 3500 pixels?
Not necessarily stupid, but it could well be problematic (certainly in an applet), and there may well be a better way of doing whatever it is you're trying to do.
Would a png reduce the time it takes to repaint?
My brother said being able to look at the hex value and not the .grabPixels() array would reduce the time it take to repaint. Is this true?
4000 x 3500 image cut in 2. Would that reduce repaint time?
Right now what is happening is u can see each picture repaint itself.
Ill put the applet on the net. www.freewebs.com/tfdk/applet.html (I hope freewebs supports applets).
Please give any suggestions that would reduce lag time. Thank you
Would a png reduce the time it takes to repaint?
Not per se, no. Images are decoded when loaded so the source is pretty much irrelevant.
My brother said being able to look at the hex value and not the .grabPixels() array would reduce the time it take to repaint. Is this true?
I'm not sure I follow. What are you doing? You don't need to grab pixels to repaint, are you manipulating the image directly in between paint cycles? If so then you can expect operations to be quite slow.
4000 x 3500 image cut in 2. Would that reduce repaint time?
Possibly. Are you using transforms to render with? If not then you can't hope to render all that on a screen so there'd probably be no harm in tiling it.
Right now what is happening is u can see each picture repaint itself.
I suspect what you have, since you're using GIFs (which are palletised) is an image which has a data transfer type different to that used by the graphics device.
Via GraphicsEnvironment and GraphicsDevice you can get GraphicsConfiguration and query its ColorModel and then its transfer type. In most cases this will be an integer type but it's best to check.
Then, from the BufferedImage you've created, get its ColorModel and the transfer type. You'll probably find with a GIF-sourced image that it's a byte type.
If the two transfer types are different then pasting the image is a costly operation: what you need to do is use the GraphicsContext to create a compatible image, then render your old image into it, and dispose of the old one.
That's a fairly undesirable step to have to go through - it'll obviosusly take a bit of processor time for an image the size of yours and there's the memory overhead of having it in memory twice as well (even though the initial image will be only a quarter the size of the compatible one, if it uses bytes instead of ints). So one thing you can do is store your image as a true-color PNG instead of a GIF - there's nothing magic about this, but what it does mean is that on decoding it you will end up with a color model and transfer type which is integer-based and will render quickly for anyone using a true-color display (which is most people).
You're doing this in an applet and an integer-based image of that size is going to cause you massive problems with heap space. You've got 96Mb to play with and that image will eat 56Mb of it. If you're having to copy a byte image to it then that's going to require an extra 14Mb overhead.
I would strongly question the wisdom of using a 4000x3500 image in an applet. What are you using it for? Can you find an alternative means of rendering the image or parts of it? - eg if a lot of it is plain-colour then can you break it into parts which only cover the non-plain sections? if there are repetitions in the image can you re-use tiles?
Oh hang on, it'd help if I checked that applet link...
WHOA! Yeah - there's no need at all for a huge image like that! You only have two background tiles, a green one and a blue one - use a data structure to lay out the tiles, eg if you wanted four green squares surrounded by a ring of blue squares you might do it like this,
int[][] map =
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
}
...though you'd be better off sticking the values in a text file and parsing it to create the map.
Hope that all helps.
there's no need at all for a huge image like that!
Hang on - it's clearly not loaded a 4000x3500 image, my console says the applet's only using half a meg of heap.
Aaaahhh... wait - do you mean you have 4000x3500 tiles?
In which case just work out which ones are on screen and render those, not all of them.
I think I'm still a little in the dark as to what it is you're doing. Maybe posting your painting code would help.
public void paint(Graphics g) {
x = 0;
y = 0;
i = 120;
g.drawString(str,20,20);
for(y = 550;y > 0;y = y - 50) {
for(x = 550;x > 0;x = x - 50) {
x = x - 50;
y = y - 50;
if(pix[i] == 1) {
g.drawImage(grass,x,y,this);
g.drawImage(person,250,250+((int)Math.random()*2+1),this);
}
if(pix[i] == 2) {
g.drawImage(water,x,y,this);
}
if(pix[i] == 3) {
test = g.drawImage(dirt,x,y,this);
}
if(pix[i] == 4) {
g.drawImage(rock,x,y,this);
}
if(pix[i] == 5) {
g.drawImage(carl,x,y,this);
}
x = x + 50;
y = y + 50;
i--;
}
}
i = 120;
}
}
Just a few things i thought i mention:
Ive been using png ever since u mentioned it lol
Im using Image not BufferedImage...dont even know what it does lol
4000 x 3500 tiles? When i stared the image in psp i just 3500 pixels by 4000 pixels.
I do only render the pixels that are actually on the screen using the PixelGrabber.
What would changing to background into an array or text file do?
www.freewebs.com/tfdk/image/map.gif - The only gif im using right now
Check it out ^^
To me having a picture is a LOT easier than having:
000000000000000000000
011111000000000000000
011111000000000000000
011111000000000000000
001111000000000000000
000111000000000000000
000011000000000000000
000000000000000000000
1 representing land
0 = water.
thanx
Right, I see what you're doing now :o)
I think the problem lies in or or both of two areas but could you post the code which loads the map image, and when is that called? ie when is the image loaded, and when is it discarded?
The applet doesn't appear to be using enough memory to hold the map image so I'm not sure what's going on there.
To me having a picture is a LOT easier than having:
For that size map you're right :o)
I dont have my source code with me right now.
its something like this:
Image map = getImage(getCodeBase(),"image/map.gif");
PixelGrapper pg = new PixelGrabber(map,x,y,11,11,pix,0,11);
pg.grabPixels();
The array pix now has the color of every pixel in the 11x11 box (starting at the top left with the x y coords.) Then i just paint (from the bottom right to the top left) all the images. I did notice that i was still using a gif for the grass, and changing that did seem to speed it up.
Should i be using BufferedImage? If so, what,why,and how.
Thanx in advanced
Eutro
Yep, thought so - that's your problem. You're reloading the image when the little man moves. That's an expensive operation (there's a large amount of memory allocation).
There are a few things you can do.
Option 1. Load the image at startup and create a byte[][] of the same dimensions. Copy the pixel data into it (assuming you have no more than 256 different cell types, but that should be safe ;o) ...note that you may have to do this in stages rather than grab all the pixels in one go. The image will occupy about 14Mb on loading, the byte[][] will occupy the same again, and if you stored an int[][] of the same size then you'd need another 56Mb - with all this combined you'd be likely to blow your 96Mb limit. And an OutOfMemoryError is a Very Bad Thing. So - you could create an int[] large enough to copy one row at a time, cast the values to bytes, insert them into your byte[][] and move on to the next row.
That gives you access to the whole map all the time without reloading the image.
2. This is a better solution. Break your image into tiles of, say, 256x256px (or whatever - powers of two are so much nicer though ;o) ...now you can load a single tile at anyone time - naturally you need to know which one you're in - and use that as an int[]. But it means you don't reload the whole image each time - you just load a tile when you move into it. You're loading thousands of pixels instead of millions so the load will be much faster.
If you're feeling smart you can detect when the player is approaching an edge of the current tile and preload the next one in a background thread so there's no lag when they actually cross the threshold - you just start using the next array.
But don't reload the map image every time the player moves: that's what's killing it right now. The aim is:
- prevent frequent reloading of the map (so load it before the player moves)
- don't blow the heap space (so used tiles instead of one huge image)
- remove any remaining lag (so load new tiles in the background before you need them)
Are you saying that i should make lots of different pictures for the map? Or when i do pixelGrab, i grab 256 x 256 at a time?
Then when its in the byte, i would go byte[x][y]?
Threads arent my best friend, as i have only started learning java 2 weeks ago. Cant i have something at the begining the paint that says:
if((x +6) == 257) {
pg = new PixelGrabber(map,x+5,y,256,256,byte2,0,256);
pg.grabPixels();
}
There would be a replica for the x coord. This would:
1. Check to see if the next out of site square is on the next tile.
2. Load the next tile into a second byte (byte2)
3. Grab Pixels.
Are you saying that i should make lots of different pictures for the map?
Yes.
As I've said - you're repeatedly loading thaat whole map, just to read an 11x11 chunk of it. Loading a 4000x3500px image is a huge operation. You minimise it by loading less of it and/or less often.
Loading it less often is easy since you can just load it at startup and keep it in memory. That gives you two problems: one is a performance overhead at startup (though only the same as you currently have every time the player moves), the second is more serious and that's the amount of memory it occupies. This is a particular problem with applets where you can't just try and claim more heap at startup. With the image being palettised you'll probably actually be fine, but regardless, it's poor memory management. So that's why you need tiles.
As a basic example, let's say you have 40x35 tiles, each of which is 100x100. At any one time, you know which tile your man is in (just divide his x,y location by the tile size). So you load that tile, grab all of the pixels from that tile and keep that array of pixels in memory.
Now when the player moves, you have the pixels ready and waiting - you don't need to load an enormous image.
The thing you then have to deal with is checking when the player crosses a tile boundary. So when they move, the following happens;
determine current tile based on new location
if current tile is different to old tile
{
load image for new tile
convert image to int array via pixel grabber
store our int array in our 'tiledata' field
}
Then when you paint, the following happens;
work out our location within the tile
get the 11x11 pixels we need to render
render them
Now you'll also find that when the player is near the edge you will have to load one or more adjacent tiles (you may at any one time need up to four tiles in memory).
How you manage this is up to you. Anticipating the movement and preloading in background threads is a more advanced stage, but at the very least you'll have to detect the player being withing 5 squares of the tile boundary and load tiles accordingly.
Or when i do pixelGrab, i grab 256 x 256 at a time?
Grabbing pixels is "a bit" slow so you don't want to be doing it too often. But the "really, really slow" thing is loading the huge image. Given that you really ought to break the image into bite-sized chunks then you can happily pixel-grab those bite-sized chunks in one go and hang on to them.
The point in having more than 11x11 pixels available at a time is that you don't have to do as much stuff when the player moves, it's already in memory.
Then when its in the byte, i would go byte[x][y]?
Yes. You could equally use byte[] but I'd be inclined to use byte[][] just for clarity.
Cant i have something at the begining the paint that says:
You're thinking along the right lines although the implementation you suggest will need a bit of refining.
If i were to make lets say...35*40 seprate pictures, then it would be hard to get the lining all up right.
Could I load the map.gif everytime they step over the boarder?
I havent worked with bytes before. When i have an integer, do i just cast it to turn it into a byte?
This is what im planning to do:
{
// All the tiles have numbers:
switch(tile) {
case 1: xx = 0;
yy = 0;
etc....
}
// pg is the PixelGrabber
for(x = 0;x < 256;x++) {
pg = new PixelGrabber(map,xx,yy,1,256,pix,0,256);
for(i = 0;i < 256;i++) {
switch (pix[i]) {
case "some random number that represents a color": pixe[x][0] = pix[i]
etc...
}
}
}
}
Sorry the code isnt that clean. I havent actually tried this yet.
If i were to make lets say...35*40 seprate pictures, then it would be hard to get the lining all up right.
Absolutely not. You've already written some code which loads an image and grab segments of it so it should take next to no time to use that knowledge to make yourself a little "map processor" tool which takes your map and then generates all the tiles by chopping up the image into smaller rectangles.
If you're using a build script (Ant or whatever) then you can even run that tool as part of your build script.
Could I load the map.gif everytime they step over the boarder?
I don't think you're getting the one fundamental thing that's underpinning your whole problem. Loading map.gif is a very expensive operation. Yes, you could load it every time they step over the border (or rather, every time they get near it). But you'd have the same delay when the user moves, and the same memory overhead of loading that huge image. It's a Very Bad Idea.
Seriously, the only sensible approach to your applet is to tile your map image, otherwise your performance and memory overheads are unreasonably large.
I havent worked with bytes before. When i have an integer, do i just cast it to turn it into a byte?
If your int value is between 127 and -128 inclusive, yes. So as long as your palettised image only contains colours with indices of 0-127 it will work. The only reason I suggested bytes is that they're a quarter of the size of ints. If you're using small tiles then it's no big deal, you can stick with ints if you prefer.
I went on holidays. Sry for the delay.
I understand what your saying now. Ive redone it with one tile of 100 x 100. You can move around till you get to the boarder, then you get an arrayofbounds exceptions, since i havent told it to load the next tile.
My brother thinks it is possible to take all the different...objects (grass, water,etc) and turn it into 1 picture. Is this possible?
Would it be faster to use BufferedImage. Its still flickering a bit.
If you have ever played runescape (dont worry i dont pay ne more :D), how would they repaint there screen every millisecond without a flicker.
Thanks in advanced
I haven't really followed the whole conversation... so forgive me if I repeat what was already said
are you just trying to draw a tile based map? If you need inspiration, you can run this old tilemap editor I wrote a while back: http://woogley.net/misc/Editor.jar
also (even older than that) is a tutorial I wrote for RisseN a few years back. Again this code is pretty old and I have found (much) better ways of doing it: http://woogley.net/misc/RisseN/
also regarding the flicker, are you using double buffering when you render?
i.e. (pay more attention to the first class)
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
class RenderPanel extends JPanel {
// create buffer
protected final BufferedImage buffer = new BufferedImage(SIZE.width,SIZE.height,BufferedImage.TYPE_INT_RGB);
protected static final Dimension SIZE = new Dimension(400,400);
protected Rectangle r; // moving rectangle
public RenderPanel() {
r = new Rectangle(10,10,100,100);
setPreferredSize(SIZE);
}
public void update() {
r.x++;
r.y++;
}
public void paintComponent(Graphics g) {
// take care of UI paints (borders etc.)
super.paintComponent(g);
// get a Graphics object to your buffer
Graphics2D gfx = buffer.createGraphics();
// clear the buffer
gfx.clearRect(0,0,getWidth(),getHeight());
// draw your stuff here using gfx
gfx.fill(r);
// render buffer to screen
g.drawImage(buffer,0,0,null);
}
}
// this just runs the above class
// dont pay much attention to it
public class Example extends JFrame {
RenderPanel r;
public Example() {
super();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
r = new RenderPanel();
getContentPane().add(r,BorderLayout.CENTER);
pack();
show();
loop();
}
protected void loop() {
while (true) {
r.update();
repaint();
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) {
new Example();
}
}
again sorry if I'm repeating stuff (too lazy to read the whole thread) :P
No. Your not repeating stuff. I have already looked at that site when searching the forums for help. It did help alot :P
Im not quite clear on that code. If you could give me your AIM / MSN that would be nice.
are you using double buffering when you render?
no. What is that lol. I only start java a few weeks ago.
Does this repaint 11 x 11 different pictures that get pixelgrabbed from the map image (www.freewebs.com/tfdk/map.gif). The version on my computer uses png. Ill put that on the internet if anyone need it. For now heres the old one: www.freewebs.com/tfdk/applet.html
Otherwise I cant really do much.
Thanks in advance,
me i guess..
Ok, ive thought of some questions that should help me get the GUI up and going.
1) What exactly is BufferedImage? How is it used (syntax), and does
this stop the flicker on the screen? Should I be using it?
2) Is it possible to paint the canvas, then display that onto the
screen? Im not entirely sure how this would be done, because I have
never worked with the Canvas class or something simular to that
before.
3) How would you load a 100x100 tile when you cross over the border of
the old one.
4) What is double buffering?
Thanks for your help!