Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Active Rendering with Swing (swing rendering off the EDT)  (Read 6763 times)
0 Members and 1 Guest are viewing this topic.
Offline CommanderKeith
« Posted 2006-10-20 18:30:57 »

Hi,

I can't reply to the old thread http://www.java-gaming.org/forums/index.php?topic=13211.30 for some reason so I've started this one.

SInce Kova has mentioned that he's interested in how all this works, here's an example.  It has 3 classes & shows how to (1) get Swing menus in your game  Cool & (2) switch between windowed & full screen exclusive mode while in the game  Cheesy.

The reason why the code is quite long is that this is doing what is meant to be impossible - rendering Swing off the EDT.  This is code that I put together myself, but which I owe all credit to Luke and David Brackeen who are responsible for the SynchronizedEventQueue & the NullRepaintManager.  Copy the 3 classes into your IDE and compile & run Main.java.  The code also works fine with the java2D OGL pipeline (except for a bug in java6 with OGL, but Chris Campbell is working on it Wink) & D3D pipeline.

Let me know if it works  Tongue,
Keith

The example files are attached to this message just below this writing, just download them & rename the file so it ends in .java,,, note that you have to be logged in as a member to see the hyper-link to the files below...

Offline CommanderKeith
« Reply #1 - Posted 2006-10-20 18:32:18 »

grrrrrrrrr.... this attachment of files is causing all kinds of problems
OK, the files show up just below this  Wink

Offline Kova

Senior Member





« Reply #2 - Posted 2006-10-21 00:51:57 »

Thank you Keith.
Hats off to Luke and David Brackeen, and a big no-no to swing team.
If anybody is interested in much simpler alternative, but requires subclassing every swing component you need (and overriding paint method), check out
http://www.java-gaming.org/forums/index.php?topic=15096.0

When just runing and closing app sometimes I get NullPointerException:
1  
2  
3  
4  
5  
Exception in thread "Thread-2" java.lang.NullPointerException
   at java.awt.Component$BltBufferStrategy.show(Unknown Source)
   at Main$CustomPanel.render(Main.java:205)
   at Main$2.run(Main.java:80)
   at java.lang.Thread.run(Unknown Source)


and sometimes when switching to full screen mode I get:

1  
2  
3  
4  
5  
6  
Exception in thread "Thread-2" java.lang.IllegalStateException: Component must have a valid peer
   at java.awt.Component$FlipBufferStrategy.flip(Unknown Source)
   at java.awt.Component$FlipBufferStrategy.show(Unknown Source)
   at Main$CustomPanel.render(Main.java:205)
   at Main$2.run(Main.java:80)
   at java.lang.Thread.run(Unknown Source)


plus JFrame's title bar is really screwed up, but I guess in active rendering you rearly use that
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline CommanderKeith
« Reply #3 - Posted 2006-10-21 06:00:56 »

When just runing and closing app sometimes I get NullPointerException:
1  
2  
3  
4  
5  
Exception in thread "Thread-2" java.lang.NullPointerException
   at java.awt.Component$BltBufferStrategy.show(Unknown Source)
   at Main$CustomPanel.render(Main.java:205)
   at Main$2.run(Main.java:80)
   at java.lang.Thread.run(Unknown Source)


See the comment I put in Main's close method.  If you wait for rendering to finish before disposing the window then this shouldn't happen.
and sometimes when switching to full screen mode I get:

1  
2  
3  
4  
5  
6  
Exception in thread "Thread-2" java.lang.IllegalStateException: Component must have a valid peer
   at java.awt.Component$FlipBufferStrategy.flip(Unknown Source)
   at java.awt.Component$FlipBufferStrategy.show(Unknown Source)
   at Main$CustomPanel.render(Main.java:205)
   at Main$2.run(Main.java:80)
   at java.lang.Thread.run(Unknown Source)


This is a bugger, I'm not sure how to get rid of it, perhaps the full screen mode code needs to be in a sync block sync'ed on SynchronizedEventQueue.MUTEX, but I think I tried that and still got the Exception.  If you can figure it out, let me know  Smiley

Quote
plus JFrame's title bar is really screwed up, but I guess in active rendering you rearly use that

Yeah, like I said in the comment in Main's constructor when setUndecorated(false) is called, the title bar shouldn't be used.  I only included it to show that resizing the window works fine with this code.

I'm glad you like it, you should try setting the Look and Feel, that was the big plus for using Swing to me.  Kirill's Substance Look and Feel is the best one I've found.  Also, since we paint the glass pane of the JFrame, you can add tooltips to buttons and they'll paint properly.  Cool, eh?  Cheesy

Offline CommanderKeith
« Reply #4 - Posted 2006-10-21 11:29:53 »

Here's the example as a Web Start link, mind you its not very exciting :

http://www.freewebs.com/commanderkeith/ActiveRenderingSwing.jnlp

It requires 'all permissions' to go into full screen mode.

Keith

Offline Kova

Senior Member





« Reply #5 - Posted 2006-10-22 18:07:44 »

ok I'm pretty much frustrated now... I've been trying to get it working all day now. I've also made a simple example and swing components draw fine but they don't get any action listeners. JTextFields are not focusable, JButtons aren't clickable and so on... they are just drawn. So please someone take a look at the code, it's very similar to sample Keith gave, and tell me what's wrong.

2 classes, each in it's file, undecorated JFrame as fullscreen app, turn of with alt+f4

Viktorije.java:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
/*
 * Created on 2006.10.21 by Kova
 */

package viktorije;

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Toolkit;

import javax.swing.JFrame;

public class Viktorije extends JFrame {

   public final static int DEFAULT_FPS = 60;
   
   public static int res_height;
   public static int res_width;
   
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////  
 
   // MAIN
  public static void main(String[] args) {
      int fps = DEFAULT_FPS;
       long period = (long) 1000.0/fps;
       System.out.println("fps: " + fps + "; period: " + period + " ms");
       new Viktorije("Viktorije", period*1000000L);     // ms --> nanosecs
  } // end: main()
 
   // CONSTRUCTOR
  public Viktorije(String title, long period) {
      super(title);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      try{
         EventQueue.invokeAndWait(new Runnable(){
            public void run() {
               NullRepaintManager.install();   // this installs the NullRepaintManager on the AWT's Event Dispatch Thread
           }
         });
      } catch (InterruptedException e) {
         e.printStackTrace();
      } catch (java.lang.reflect.InvocationTargetException e) {
         e.printStackTrace();
      }
      SynchronizedEventQueue.use();      // this stops the AWT's Event Dispatch Thread from modifying the Swing menus at the same time we paint them.
     setIgnoreRepaint(true);
      setUndecorated(true);
      Dimension screen_dim = Toolkit.getDefaultToolkit().getScreenSize();
      res_width = (int)screen_dim.getWidth();
      res_height = (int)screen_dim.getHeight();
      setBounds(0,0,res_width,res_height);
      setResizable(false);

      setVisible(true);   // must be called before createBufferStrategy() or exception is thrown, don't know why
     synchronized(SynchronizedEventQueue.MUTEX){
         createBufferStrategy(2);
      }
     
      ViktorijePanel viktorije_panel = new ViktorijePanel(this, period);
      setContentPane(viktorije_panel);
     
      viktorije_panel.startAnim();      // Kova: starts game loop thread
  }

}


ViktorijePanel.java:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
package viktorije;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferStrategy;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class ViktorijePanel extends JPanel implements Runnable {
   
   private Thread animator;  
   
   private volatile boolean running = false;
   private boolean game_over = false;
   
   private GraphicsDevice device;
   private DisplayMode display_mode;
   private BufferStrategy buffer_strategy;
   private Viktorije viktorije;
   
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////

   // CONSTRUCTOR
  public ViktorijePanel(Viktorije viktorije, long period) {
      this.viktorije = viktorije;
      this.buffer_strategy = viktorije.getBufferStrategy();
      setIgnoreRepaint(true);
      setOpaque(true);
       
       setLayout(null);
       JTextField tf = new JTextField("TEST ... use ALT+F4 to shutdown");
       JButton btn = new JButton("press this to exit");
       btn.setBounds(200,300,150,25);
//       btn.addActionListener(new ActionListener() {      // dosen't work, but even if it works this shouldn't be neccessarry
//         public void actionPerformed(ActionEvent e) {
//            System.exit(0);
//         }
//       });
      tf.setBounds(200,200,200,20);
       add(tf);
       add(btn);
//       viktorije.requestFocus();   // dosen't work
//       this.requestFocus();      // also dosen'w work
  }  // end: constructor
 
   public void paint(Graphics g) {
      System.out.println("ViktorijePanel.paint(): this should rarely (best never) be called");
   }
   
   // Kova: start main game thread ("Viktorije Animator")
  public void startAnim() {
      if (animator == null || !running) {
           animator = new Thread(this, "Viktorije Animator");
           animator.start();
      }
   } // kraj: startAnim()

   // Kova: start main game thread
  public void run() {
       running = true;
       GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
       device = environment.getDefaultScreenDevice();
       display_mode = new DisplayMode(1024,768,32,DisplayMode.REFRESH_RATE_UNKNOWN);
       System.out.println("device.isFullScreenSupported() == " + device.isFullScreenSupported());

       while(running) {
          gameUpdate();   // Kova: update game state
          gameRender();   // Kova: render the game to a buffer
          paintScreen();  // Kova: draw the buffer on-screen              
          sleep();
       }
       
   } // end: run()

   private void sleep() {
      try {
         Thread.sleep(20);   // Kova: 50 fps
       } catch (InterruptedException e) {
           e.printStackTrace();
        }
   }

   // Kova: update game state for 1 tick
  private void gameUpdate() {}

   private void gameRender() {
      Graphics2D g2d = null;
      synchronized (SynchronizedEventQueue.MUTEX){
         g2d = (Graphics2D)buffer_strategy.getDrawGraphics();   // CommanderKeith: must sync this or else there can be Exceptions thrown when resizing window (especially in OGL mode).
     }
     
      g2d.setColor(Color.GREEN);
       g2d.fillRect(0, 0, Viktorije.res_width, Viktorije.res_height);      // Kova: clear the background

       g2d.setColor(Color.white);
       g2d.fillRect(0, 45, Viktorije.res_width, 6);  
   
       g2d.setColor(Color.BLACK);
        g2d.drawString("say: ", 25, 725);

      synchronized (SynchronizedEventQueue.MUTEX){
         this.paintComponents(g2d);
         viktorije.getGlassPane().paint(g2d); // paint glass pane to paint tool tips  
     }
   }  // end of gameRender()

   private void paintScreen() {
       try {
          buffer_strategy.show();
           Toolkit.getDefaultToolkit().sync();                 // Sync the display on some systems (on Linux, this fixes event queue problems)
      }
       catch (Exception e) { // quite commonly seen at applet destruction
         System.out.println("Graphics error: " + e);
          e.printStackTrace();
       }
   } // end of paintScreen()

   public void setFullScreen(boolean fullScreen) throws IllegalArgumentException {
      if (isFullScreen() == fullScreen) {
         return;            // CommanderKeith: we're already in fullscreen, so return.
     }
      if (fullScreen) {
         viktorije.setResizable(false);
         device.setFullScreenWindow(viktorije);
         if (display_mode != null && device.isDisplayChangeSupported()) {
            try {
               device.setDisplayMode(display_mode);
               System.out.println("display mode set");
            } catch (IllegalArgumentException e) {
               System.out.println("display mode not supported");
               device.setFullScreenWindow(null);
               viktorije.setResizable(true);
               throw e;
            }
         } else {
            device.setFullScreenWindow(null);
            viktorije.setResizable(true);
            throw new IllegalArgumentException("device.isDisplayChangeSupported() == false");
         }
      } else {
         device.setFullScreenWindow(null);
         viktorije.setResizable(true);
      }
      viktorije.createBufferStrategy(2);
      this.buffer_strategy = viktorije.getBufferStrategy();
   }
   
   public boolean isFullScreen() {
      if (device.getFullScreenWindow() == null){
         return false;
      }
      return true;
   }

}  // end: ViktorijePanel
Offline CommanderKeith
« Reply #6 - Posted 2006-10-23 11:01:23 »

Your inner panel 'ViktorijePanel' has zero width & height so it's not reacting to anything.

Insert this in its constructor & it will work:
setSize(400,400);

Its funny that its child components still paint.  I bet that the same problem would have happened without the active rendering code, its just that you would've seen nothing painted so the zero size problem would have been more apparent.  Maybe try to get the GUI working with normal swing first and then transform it using the Active Rendering technique.  Swing is tricky enough without hacks like what we're using here  Undecided

Thanks for trying it out.  Best wishes with your project,

Keith

Offline Kova

Senior Member





« Reply #7 - Posted 2006-10-23 12:58:49 »

Insert this in its constructor & it will work:
setSize(400,400);

Thanks a lot Keith, don't believe I forgot that.... components being painted throw me off since I'm not used to this new concept of manually painting swing. Smiley  Actually it's not strange at all that they were painted since I was the one that called paintComponents() wich usually wouldn't be called until they are visible I guess. It's working fine, swing paints when I do it Smiley .. this also shows that paint methodes in swing do just that, paint, and deceiding wheter to paint or not isn't included there but in some pre logic, which is logical Smiley On the other hand this is one more thing I have to worry about, is a component visible so I can paint it. It will be pretty much simple in my game since it's all absolute, but this will give headaches to someone using not so strict interface.

Its funny that its child components still paint.  I bet that the same problem would have happened without the active rendering code, its just that you would've seen nothing painted so the zero size problem would have been more apparent.  Maybe try to get the GUI working with normal swing first and then transform it using the Active Rendering technique.  Swing is tricky enough without hacks like what we're using here  Undecided

So you think paint methodes are the one that deceide to paint or not... hmm, maybe. I can't really test GUI as normal first, becouse those are 2 different things of doing it, not comparable, so I don't know what you mean that there would be same problem with non active rendering. It's clear that if panel has no dimension that it wouldn't be painted.

Thanks for trying it out.  Best wishes with your project,
Thank you, to you also
Offline Kova

Senior Member





« Reply #8 - Posted 2006-10-24 17:43:55 »

One more thing Keith (and whoever used this), did you notice fps drop after you applied this technicque? On my faster computer I didn't noticed since it's always 60, which is max, but on my slower one fps dropped from 55 to 44, and that's not so good, looks pretty choppy. I tested if it was changing from manually double buffering to buffer strategy, but it isn't it, my test shows that buffer strategy should be faster.
I'm under impression that this is due to synchronizing before drawing.
Offline CommanderKeith
« Reply #9 - Posted 2006-10-25 05:54:51 »

Yeah, FPS did drop, but its not a big deal so long as you keep the Swing painting (the bit that's synchronized) to a minimum.  Also, cut down on how many layers of background Swing paints.  I set the background of my JInternalFrame menu see-through, that way there's no double-filling.

For my game I just have a little tiny 'menu' JButton which is painted in the corner of the screen on top of the rest of the game's graphics.  For big game menus like options dailogs, a slower FPS shouldn't matter.

Also, the synchronized blocks will only significantly drag on performance when the lock is 'in contention' - ie when the sync'ed code has to actually wait for the other sync'ed code. 

One work-around to having to sync at all would be too paint an image of the menuButton, and detect its presses using a normal MouseListener.  Then when that's pressed, paint the big sync'ed Swing menu on top of the game graphics.

Keith.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Kova

Senior Member





« Reply #10 - Posted 2006-10-25 18:18:57 »

well that is the problem... I would understand if I had a big menu that I'm rendering in the game... but for now I don't have a single swing component in animation Smiley Just for main menu wich isn't displayed during game animation of course.

This is how I do it: Viktorije is JFrame, ViktorijePanel is a JPanel. I put ViktorijePanel as content pane of Viktorije and set card layout to it (only one component visible at a time). Then I create few JPanels with swing components, each representing a menu or a sub menu of main menu, like host game submenu, connect to submenu, settings sub menu and so on. I add them all to ViktorijePanel and I add a animation JPanel also. When I want to display some menu, I use layout.show() to display adequate JPanel with swing components for that menu. That's all I do. When game is running animation JPanel is displayed and all others are not visible. In animation panel I don't have a single swing component, it's basicly just an empty JPanel for now, so why the drop in fps?? I've put setOpaque(false) on both ViktorijePanel and animation JPanel. What am I missing here?

p.s. unrelated to the problem, but now when I render swing I can turn off double buffering for it? Does it hurt / have effect if I leave it on?
Offline CommanderKeith
« Reply #11 - Posted 2006-10-25 18:53:36 »

So do you still call:

synchronized (SynchronizedEventQueue.MUTEX){
      this.paintComponents(g2d);
      viktorije.getGlassPane().paint(g2d); // paint glass pane to paint tool tips   
}

because you shouldn't need to.  When you don;t call this then I can't see why the sync'ed Swing rendering could cause a slow down since there shouldn't be any contention on the lock SynchronizedEventQueue.MUTEX since it will only be called by the EDT when you move the mouse & press keys.

PS: double-buffering swing as well as using you BufferStrategy is pointless- its just triple-buffering which can only make things slower.

Offline Kova

Senior Member





« Reply #12 - Posted 2006-10-25 19:50:29 »

yes I still call the synchronized paint() ... but I expect that paint() returns immediatly since components aren't visible... or am I wrong? When I commented out that part it went back to 56 fps Smiley Thank you Keith once again, but what is swing good for if I can't paint it? Smiley This is killing my fps to bad to accept it, a 20% slower game just for few gui components is too too too much. And only if it was just slower, fps drops but there's also a stall in rendering which is very visible so game jumps. And when I add incorectly (or not at all) rendered swing components (drop down menu with custom cell color renderer) on top of that, I think I will go back to passive rendering of swing and activly rendering of game animation, but with swing components rendered as I first did it, subclassed with overriden paint to paint to buffered image, and then draw that image when activly rendering.

...who would have guessed that synchronizing on a paint that probably returns immediatly is so time consuming Sad
btw. that computer that I was using for testing is a AMD Athlon 2600+ with Radeon 9000pro, so It's not slow at all, It can run CoD2 with ~40 fps.
Offline CommanderKeith
« Reply #13 - Posted 2006-10-26 05:00:07 »

I think that what might be happening is that your CardLayout is being circumvented by the direct call to paintComponents(...) so maybe all layers are being painted, instead of just the one that's meant to be visible, so check that.  I'd avoid CardLayout, in my game I just add and remove components when the time comes.

Also, I have not been able to get Swing to revert from active to passive rendering yet, though I didn't try very hard.  Please let me know if you figure out a way to do it!

Thanks,
Keith

Offline Kova

Senior Member





« Reply #14 - Posted 2006-10-26 17:07:55 »

Funny thing... today as I started working on project as I commented synchronized part animation stayed at 44 fps. I clearly remember yesterday when reading your post that I just commented that sync part and it came back to 55 fps, and now it dosen't work. I've been trying to get it to 55 again all day Smiley This is all too much to debug so I'll revert to revision before conversion and start all over again with new experience I got.

I think that what might be happening is that your CardLayout is being circumvented by the direct call to paintComponents(...) so maybe all layers are being painted, instead of just the one that's meant to be visible, so check that.  I'd avoid CardLayout, in my game I just add and remove components when the time comes.

If that was the case I would see all of menues on top of each other, and fps would be much lower then, becouse if I draw even one submenu while rendering game animation fps drops to 30. Submenus are quite rich of options. I think paintComponents() is always called, no matter of layout, and then it's layout deceides what to draw in those inner paint methodes. Note to all that this is controary to what I've said before here in reply #7, when I got components painted but they were not reacting Smiley ... ah is there someone who will understand swing ever? Smiley
CardLayout is cool and I had no problems with it, one of few things in swing that works as I expected. I think it's much more logical and simpler than adding/removing components every time you change gui.

Also, I have not been able to get Swing to revert from active to passive rendering yet, though I didn't try very hard.  Please let me know if you figure out a way to do it!

well I'm not actually switching between active/passive, first I have swing main menu which is passive, and then when user starts the game, game uses active rendering, where I activly render swing components that I subclassed. When you want to go back to main menu (without quiting game loop thread) you pause your game and show (or add to visible container as you do it Wink ) main menu which is still passively rendered.
Offline CommanderKeith
« Reply #15 - Posted 2006-10-27 22:59:02 »

well I'm not actually switching between active/passive, first I have swing main menu which is passive, and then when user starts the game, game uses active rendering, where I activly render swing components that I subclassed. When you want to go back to main menu (without quiting game loop thread) you pause your game and show (or add to visible container as you do it Wink ) main menu which is still passively rendered.

Ah, great!  So what is your actual code to un-active render Swing?  I presume you call set setIgnoreRepaint(false); and uninstall the RepaintManager & SynchronizedEventQueue?

Thanks,
Keith

Offline Kova

Senior Member





« Reply #16 - Posted 2006-10-27 23:52:16 »

well I'm not actually switching between active/passive, first I have swing main menu which is passive, and then when user starts the game, game uses active rendering, where I activly render swing components that I subclassed. When you want to go back to main menu (without quiting game loop thread) you pause your game and show (or add to visible container as you do it Wink ) main menu which is still passively rendered.
Ah, great!  So what is your actual code to un-active render Swing?  I presume you call set setIgnoreRepaint(false); and uninstall the RepaintManager & SynchronizedEventQueue?

heh, you didn't got it Wink , let's try this way: it's all passive, all doing paints at os/app requests. The only difference is that I have my components where I overriden paint() to paint on my BufferedImage instead on screen, so when time comes for active rendering I render that BufferedImage. Here is an example of subclassed JTextField:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
    static class BufferedJTextField extends JTextField {
       BufferedImage image;   // Kova: every app triggered repaint store here and use this when doing active rendering
       int bi_width;
        int bi_height;

        public void paint(Graphics g) {
            synchronized (this) {
                int width = getWidth();
                int height = getHeight();
                if (width <= 0 || height <= 0) return;
                if (image == null || width != bi_width || height != bi_height) {                    
                   image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
                    bi_width = width;
                    bi_height = height;
                }
                Graphics g2 = image.createGraphics();
                try{
                    super.paint(g2);
                } finally {
                   g2.dispose();
                }
                g.drawImage(image, 0, 0, null);
            } // end: synchronized
       } // end: paint()

    } // end: BufferedJTextField class
....
....
chat_textfield = new BufferedJTextField();
...setbounds, addactionlistener, container.add...
....
....


in redering method:
1  
2  
3  
4  
5  
6  
        synchronized(chat_tf) { // Kova: drawing swing componets in active rendering...
           Image image = chat_tf.image;
            if(image != null) {
                g2d.drawImage(image, chat_tf.getX(), chat_tf.getY(), null);
            }
        }


the code is not mine actually, I just adjusted it. The idea came from leouser from JavaDesktop->Swing forums. I asked on newless clubbies about it and posted this solution, read here. I know someone posted on "pearls of wisdom" not to synchronize on swing components becouse something else also does it, don't remember what exactly, but I'll trust in leouser's code for now since I'm under impression he mastered swing Smiley Later I'll check why is it sychronized, when I have some time for long, low gain researches.
Offline Kova

Senior Member





« Reply #17 - Posted 2006-10-30 19:57:22 »

to put this to a close: activly rendering swing didn't slow my game down, but I still wont use it since it has problems rendering custom stuff. Don't know why my game slow down, on 2nd (slower) computer. On my primary computer the new version with buffer strategy is ~2fps faster, and on slower computer it is ~10 fps slower, strange huh? Smiley
Offline CommanderKeith
« Reply #18 - Posted 2006-11-04 07:45:23 »

I've been trying to adapt my game so that it can be an Applet but I think it's imossible. 

The problem is that Applets don't have a BufferStrategy, unlike a Window.  Usually you get around this by putting a Canvas in the Applet, but Canvas is not a Container so it can't hold Swing components.

I've been bending over backwards to get Swing components working inside the Canvas (by adding both to a JComponent) and while I can get my menus to paint and take keyboard input, I can't get them to take mouse input.  The Canvas steels it and I can't figure out how to get it to work, even if the Canvas is unfocusable.  After searching this topic, apparently the heavyweight Canvas just doesn't play with Swing. 

So does anyone know a solution?  Basically I need to get MouseInput from the Canvas and give it to Swing components.

Or is it the case that if you want to use a BufferStrategy with direct-rendering Swing in an Applet, forget it.

Thanks,
Keith

Offline fletchergames

Senior Member





« Reply #19 - Posted 2006-11-04 18:06:58 »

I was working on an applet not too long ago (it's an application now).  I didn't do anything with BufferStrategy.

Instead, I just set up a normal Swing gui.  Instead of having a Canvas for the main panel, I just overrode the paintComponent method of the JPanel for the main panel and drew all the game objects there.  If you want some of them to appear on top of the Swing components, you'll have to override the paint method.  It'll have to look something like this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
public void paint(final Graphics g) {
//draw layer under Swing components
[your code here]

//paint the components
super.paint(g);

//paint the top layer above the Swing components
[your code here]
}


I had a method like that in another game (which wasn't an applet).

You can call setIgnoreRepaint(false) on your main frame and then just call the repaint method during your main loop to do active rendering.  (The repaint method still works when the repaint is ignored - it just doesn't seem to get called unless you call it directly.)  I needed the windowActivated and windowDeactivated methods in the application version, but I don't think I needed them in the applet version.
Offline CommanderKeith
« Reply #20 - Posted 2006-11-05 16:20:58 »

Thanks fletchergames.  You are using Swing's double-buffering then which must be some kind of VolatileImage rather than a BufferStrategy.  I suppose I'll have to do that kind of double-buffering also.  It's a real pity that Applets don't have their own BufferStrategy like Windows.  Because porting an app to become an applet is meant to be painless.  I can't see a reason why Applet should not have a BufferStrategy.  Maybe I'll post it as an RFE.

You can call setIgnoreRepaint(false) on your main frame and then just call the repaint method during your main loop to do active rendering.  (The repaint method still works when the repaint is ignored - it just doesn't seem to get called unless you call it directly.) 

Sounds like using repaint() is working for you, but its not really active rendering since your painting will be done in Swing's Event Dispatch Thread.  Repaint() will just put a paint request in the EDT's EventQueue, rather than painting straight away on the thread that you called repaint from.

Offline fletchergames

Senior Member





« Reply #21 - Posted 2006-11-06 04:09:32 »

I thought you were supposed to paint to Swing components from the EventQueue because Swing components aren't synchronized.
Offline CommanderKeith
« Reply #22 - Posted 2006-11-06 07:02:32 »

That's right.  That's why you can't paint Swing components in your without calling repaint() like what you're doing or using the solution given here to synchronise the EDT with your game loop thread.

Offline Kova

Senior Member





« Reply #23 - Posted 2006-11-06 14:14:35 »

I thought you were supposed to paint to Swing components from the EventQueue because Swing components aren't synchronized.

except for the Applet thing, we're discussing just that, painting swing in our thread
Offline CommanderKeith
« Reply #24 - Posted 2007-02-17 14:17:24 »

For the benefit of anyone still interested in this stuff, I just did a benchmark of

active-rendering Swing using the SynchronizedEventQueue      vs    passive rendering Swing using SwingUtilities.invokeAndWait(Runnable);

The active rendering was twice as fast (500FPS vs 250FPS).  I hazard a guess that this is probably because synchronizing is quicker than starting a new thread which is run while the EDT pauses.

So the moral of the story is: if you want Swing in your game use active rendering like is done in the file SwingActiveRendering.java below!

The three files needed are attached below this message.  (note that you won't see them unless you're logged in as a member)  Wink

Keith

Offline Kova

Senior Member





« Reply #25 - Posted 2007-02-17 21:47:35 »

So the moral of the story is: if you want Swing in your game use active rendering like is done in the file SwingActiveRendering.java below!

I must add that this is tricky, and it doesn't work all the times (example, my custom color picker doesn't work, doesn't render well). There is alternative which doesn't mess with events and repaint managers, but you must subclass every swing component you are want to use. I described it here somewhere.
Offline beowulf03809

Junior Member




We live for the code, we die for the code


« Reply #26 - Posted 2007-03-19 20:25:50 »

For the benefit of anyone still interested in this stuff...


Thanx!  I am most definetly still interrested in this subject (just desperately lacking in time lately).
Offline Tennie

Senior Newbie





« Reply #27 - Posted 2007-03-19 21:12:34 »

Please don't kill me for asking this question....

but in terms of practicality, what's the difference between 500FPS and 250 FPS? arent both incredibly faster than the eye can process anyway?



Oh and I posted a question related to passive rendering in swing in the newless clubbies section, so if anyone has time, please check that out at: http://www.java-gaming.org/forums/index.php?topic=16269.0

Thanks a ton Cool

Some people become relaxed and/or feel at peace with themselves/the universe because they smoke, pray, or meditate. Me, I code.
Offline Kova

Senior Member





« Reply #28 - Posted 2007-03-19 23:08:36 »

but in terms of practicality, what's the difference between 500FPS and 250 FPS? arent both incredibly faster than the eye can process anyway?

250 fps = you can add more stuff to the game and keep it playable
500 fps = you can add twice as more stuff Smiley
Offline Corale

Junior Newbie





« Reply #29 - Posted 2007-07-19 13:24:43 »

I am giving this a bump while saying thank you guys! It's a topic not to be forgotten, and that goes for the predecessor too.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CogWheelz (13 views)
2014-07-30 21:08:39

Riven (21 views)
2014-07-29 18:09:19

Riven (14 views)
2014-07-29 18:08:52

Dwinin (12 views)
2014-07-29 10:59:34

E.R. Fleming (32 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (42 views)
2014-07-24 01:59:36

Riven (42 views)
2014-07-23 21:16:32

Riven (29 views)
2014-07-23 21:07:15

Riven (30 views)
2014-07-23 20:56:16
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!