Slow fade effect

Hi!

I’m using the following code to do a fade transition effect between two images:


      public void render(Graphics g, Image imageFrom, Image imageTo, int width, int height) {
 
            BufferedImage buffer=gc.createCompatibleImage(width,height);
 
            Graphics2D g2 = (Graphics2D)buffer.getGraphics();  
                                
            int counter=0;
            while (counter<90) {
                  counter=counter+2;
                  double alphaScalar = Math.sin(Math.toRadians(counter)); 
 
                  g2.setComposite(AlphaComposite.SrcOver);
                  g2.drawImage(imageFrom, 0, 0, null);  
                  g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float)alphaScalar));
                  g2.drawImage(imageTo, 0, 0, null);
                  g.drawImage(buffer, 0, 0, null);
                  try {
                        Thread.sleep(5);  
                  }
                  catch(InterruptedException ex){}
            }                                                                    
            
            g.dispose();
            g2.dispose();
            buffer.flush();
      }
 

My main problem is that using a buffer to save the image composite before drawing it over the panel’s Graphic context slows the effect considerably. I have other effects (scrolling, sliding and some more) which don’t require the use of an intermediate buffer and they are way faster without it. I’m looking for a way to improve the perfomance of my fade effect. I’ve tried to draw the image composite over the panel’s Graphic context directly (no buffer) but the screen flickers. Can anyone help me, please ?

Regards

Before you ask me, I’ve already tried to use the BufferStrategy class instead of my intermediate buffer with fairly similar results. I cannot use FSEM, therefore I’m unable to use the page flipping, and I have to resort to blit the contents from the buffer unto the panel’s graphic context. Is there any way to speed up blit operations in java ?

this is kind of off the subject, because I don’t have an answer for you.

anyway just because you can’t use FSEM doesn’t mean you can’t use BufferStrategy. BufferStrategy can work in a windowed JFrame. Or if you’re stuck with AWT, did you know Canvas supports BufferStrategy? :stuck_out_tongue:

either way, I doubt that would help alot, since you already said BufferStrategy wasn’t much faster for you…

The problem with the slowness is that you create a new BufferedImage every frame of your rendering. This is completely unnecessary. Take out that intermediate image. Draw it straight on to your destination. Also… you never even use ‘g’. Why is it there and why do you dispose it if you never draw anything on it? By the structure of your code I would assume that ‘g’ is the Graphics object for your screen buffer. So remove the ‘buffer’ and ‘g2’ obects and just draw onto ‘g’.

This is exactly what I do in Rimscape to fade images. What you’ll want to do in drawing on ‘g’ is draw one image at (float)alphaScalar and the other image at 1f - (float)alphaScalar.

Malokhan, buddy, I think you’re head is a bit clouded today :stuck_out_tongue:

[quote]The problem with the slowness is that you create a new BufferedImage every frame of your rendering.
[/quote]
I don’t know where you see that. That render method is actually rendering 90 frames. Notice his code:


while (counter<90) {
  ... rendering ...
  try {
    Thread.sleep(5);
  }
  catch (InterruptedException e) {}

again, look at his code:


g.drawImage(buffer, 0, 0, null);

maybe you need a nap Malo :wink:

haha whoops :wink: Yes it’s not re-created EVERY frame, but it’s existance can still be done without. Sorry for the misreadings… new years, you know :wink: Yeah, the advice still holds though. You don’t need that buffer at all.

EDIT: Another idea you could try in keeping the buffer would be to draw imageFrom once on your buffer, and then each from draw on imageTo with a constant alpha, like .01f and see how that works. It might produce a similar effect to just slowly add on the new image, rather than totally redraw the whole effect each frame.

[quote]haha whoops :wink: Yes it’s not re-created EVERY frame, but it’s existance can still be done without. Sorry for the misreadings… new years, you know :wink: Yeah, the advice still holds though. You don’t need that buffer at all.
[/quote]
I’ve already tried to draw directly unto the panel’s graphic context resulting in an annoying ghosting effect between the two images which doesn’t appear if I use that intermediate buffer to draw the composite.

BTW, I know it’s the buffer slowing the effect to a crawl, thanks for reminding me of this. I have other effects (scrolling and sliding) where I draw directly unto the panel’s graphic context (no intermediate buffer) and they are pretty fast.

I’d like to know how to make the same effect without using this buffer.

does Rimscape do the effect you’re looking for? Try changing from one menu to another and see it.

[quote]does Rimscape do the effect you’re looking for? Try changing from one menu to another and see it.
[/quote]
I’ve tried playing your game without success. BTW, do you mean this thread ?

http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=2D;action=display;num=1103525254

Could I see the new code for your ScreenFader class ?

Thanks

Bummer!! What OS are you on. Does the game say it sent me an error message? I’d like to find out what’s wrong with that so I’ll check the logs just in case. Here’s the ScreenFader class now:

import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

/**
 * @author Malohkan
 */
public class ScreenFader {

      int[]            pixelsToAdd;
      double            currentAlpha, totalAlpha, currentTicks;
      final double      MAX_TICKS = 6;
      
      int                  xOffset, yOffset, w, h;
      
      BufferedImage      backGround, foreGround;
      
      public ScreenFader(int width, int height) {
            
            totalAlpha = 255;
      }
      
      public void setBackground(BufferedImage image) {
          
          backGround = image;
      }
      
      public void setForeGround(BufferedImage image) {
          
            totalAlpha = 0;
            currentTicks = 0;
            currentAlpha = 0;
            
            foreGround = image;
      }
      
      public void run(double ticks) {
          currentTicks += ticks;
          currentAlpha = 255d*currentTicks/MAX_TICKS - currentAlpha;
      
          totalAlpha += currentAlpha;
            
      }
      
      public void render(Graphics2D g2d) {
            
          Composite c = g2d.getComposite();
          
          g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f - (float)(totalAlpha/255.0)));
          g2d.drawImage(backGround, 0, 0, null);
          g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float)(totalAlpha/255.0)));
          g2d.drawImage(foreGround, 0, 0, null);
          
          g2d.setComposite(c);
      }
      
      public boolean isActive() {
            return totalAlpha < 255;
      }
}

[quote]Bummer!! What OS are you on. Does the game say it sent me an error message? I’d like to find out what’s wrong with that so I’ll check the logs just in case.
[/quote]
Sorry, it was my fault :P. It works nicely, a bit slow in my computer, though.

I copied your render() code and I get that annoying ghosting effect still. I don’t know what I’m doing wrong. :-/
How do you call the render() op ?

explain what you mean by “ghosting” please.

If I’m drawing the fade effect it’s render method is called and nothing else.

I used to have a link to some really cool pixel based tutorials for fading… The links were gone, but I tracked down the author Remon Van Vliet and he put them back online:

http://www.codeberry.com/tutorials/tutorial-1-2-1.html

This might be right up your alley Leemon…

yeah that guy rocks :slight_smile: That page is where I got my code to saturate images with color.