CommanderKeith
|
 |
«
Posted
2006-04-08 16:10:20 » |
|
Hi,
I just gave up on the roll-my-own GUI and converted to Swing - its what I know and its beautiful. I use direct rendering in my game loop thread and while I know that painting Swing/AWT components directly from such a thread is not safe, I read in a book somewhere that you can stop the AWT Event dispatching thread from painting by installing a 'NullRepaintManager', a class you make as a sub-class of RepaintManager that over-rides:
public void addInvalidComponent(JComponent c) public void markComponentDirty(JComponent c) public void addDirtyRegion(JComponent c) public void paintDirtyRegions()
with empty method bodies. You install it as follows::
RepaintManager rm = new NullRepaintManager(); rm.setDoubleBufferingEnabled(false); RepaintManager.setCurrentManager(rm);
Apparently that stops 'OS-level' paint requests but I'm not sure if it stops internal painting on the AWT Event thread. I did this to stop the AWT Event dispactching thread from painting so I can call aSwingComponent.paint(myGraphics) from my game thread without threading problems. It seemed to work fine at first, but sometimes my game freezes and I fear that its because there is a thread conflict. I assume its because things like JTextFields paint themselves (like the flashing caret) on some thread (the Event Dispatching thread?) which conflicts with the painting of that JTextField in my game loop thread.
How can I stop painting in the Event Dispatching thread for good or am I barking up the wrong tree?
Thanks, Keith
|
|
|
|
Jeff
|
 |
«
Reply #1 - Posted
2006-04-08 19:34:29 » |
|
"Use the setIgnoreRepaint method on your application window and components to turn off all paint events dispatched from the operating system completely, since these may be called during inappropriate times, or worse, end up calling paint, which can lead to race conditions between the AWT event thread and your rendering loop." http://java.sun.com/docs/books/tutorial/extra/fullscreen/rendering.htmlThis is pretty m,uch vrigin territory though so expect some gotcha's you'll have to figure out yourself.
|
|
|
|
CommanderKeith
|
 |
«
Reply #2 - Posted
2006-04-09 14:05:36 » |
|
Thanks Jeff, I'll give it a go.
That article in the java tutorial is a relief because all other Sun documentation says that Swing components can't be painted from any thread except the Event Dispatch thread....
Hopefully someone has used Swing in a direct-rendering game and can verify that it can be made to work.
If I do get it working I'll post my experiences here.
Keith
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Ask_Hjorth_Larsen
Junior Member  
Java games rock!
|
 |
«
Reply #3 - Posted
2006-04-09 14:55:41 » |
|
You can also use the invokeAndWait (or invokeLater) method of javax.swing.SwingUtilities, that will allow you execute code in the Event Dispatch Thread. If you execute all the game code there eventually then it's much easier to have normal swing components as game controls, because you won't have to queue and synchronize everything.
|
|
|
|
|
Jeff
|
 |
«
Reply #4 - Posted
2006-04-09 21:35:04 » |
|
If you let Swing/AWT render your game then (a) You lose performance. (b) You lose predictability (when a paint actually happens is some-random-measure-of-time-after-the-repaint-is-called)
In general hthis works okay for non-action games, but for action games whre frame rate and close timing are critical, Id recommend against such a technique.
|
|
|
|
Jeff
|
 |
«
Reply #5 - Posted
2006-04-09 21:42:38 » |
|
That article in the java tutorial is a relief because all other Sun documentation says that Swing components can't be painted from any thread except the Event Dispatch thread....
All the other articles youve read assume you are using Swing/AWT. If you were then yes, yo uwoudl have yo paint from the EVent thread because Swing is not thread safe. In this case you are totally by passing those mechanisms and turnign off Swing/AWT rendering entirely so its safe to paint from antoher thread. You still shoudl only paint from one thread though. (in active rendered apps this is generally your own game thread.)
|
|
|
|
CommanderKeith
|
 |
«
Reply #6 - Posted
2006-04-11 02:32:47 » |
|
I'm really confused about this... there's conflicting info out there.
Although the AWT event thread can't paint the Swing components because I turned that off, it can still modify the state of the components at the same time I paint them from my game thread.
For example, what if I paint a JButton from my game thread while its state is being changed in the AWT Event thread when the button is rolled over whith the mouse (or the JTextField is typed into, etc). So how can I possibly paint Swing components from my own thread??? I fear this is why my game freezes when I play around with the Swing menus I added.
Thanks, Keith
|
|
|
|
Jeff
|
 |
«
Reply #7 - Posted
2006-04-11 02:42:19 » |
|
I'm really confused about this... there's conflicting info out there.
Although the AWT event thread can't paint the Swing components because I turned that off, it can still modify the state of the components at the same time I paint them from my game thread.
Painting does not modify model state so its perfectly safe as long as you dont re-enter the paint code. I've never seen an issue with modifying the model from outside of the AWT threads. If you want to be sure though, ask the guys in the JavaDesktop forums.
|
|
|
|
CommanderKeith
|
 |
«
Reply #8 - Posted
2006-04-11 04:11:20 » |
|
Painting does not modify model state so its perfectly safe as long as you dont re-enter the paint code.
Great, I wasn't aware of that. I wonder how that works because if I type delete (runs in AWT Event Thread) in a JTextField and remove a character mid-way through my game thread's paint, you'd think that there'd be an ArrayOutOfBoundsException or the like thrown when the game thread tries to paint the character that no longer exists. This hasn't happened though, when I hold down delete in the JTextField after a short time my game thread just freezes and stops painting anything.... Anyhow, I'll make sure its not because I'm re-entering the paint code accidentally. Cheers, Keith
|
|
|
|
DaveLloyd
Junior Member  
Making things happen fast with Java!
|
 |
«
Reply #9 - Posted
2006-04-11 14:51:53 » |
|
Yep, Swing on JOGL works fine for me. Ignore repaints and repaint the swing parts afresh each frame.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
CommanderKeith
|
 |
«
Reply #10 - Posted
2006-04-11 15:25:24 » |
|
Thanks Dave, that's good to know. Unfortunately my experiences are of deadlocking. And I just found these articles that its unsafe to use Swing at all unless its from the Event dispatch thread (EDT). From a Sun developers blog site - http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html"Initially there was a rule that it is safe to create and use Swing components until they are realized but this rule is not valid any more, and now it is recommended to interact with Swing from EDT only" And this on the Java Tutorial site - http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html"To avoid the possibility of deadlock, you must take extreme care that Swing components and models are created, modified, and queried only from the event-dispatching thread. " The above tell me that Swing cannot be directly-rendered (ie painted directly in a separate game thread). But this conflicts with the full-screen mode tutorial - http://java.sun.com/docs/books/tutorial/extra/fullscreen/rendering.html: "Feel free to call Swing methods such as paintComponents, paintComponent, paintBorder, and paintChildren directly from your rendering loop" For my Swing menus I have only had deadlocks a couple of times, but the JTextFields I use reliably cause AWT Event thread deadlocks when I type or delete characters. What kind of Swing components are you using in your game? Maybe it only works because you use simple components which rarely cause a dead-lock with your game thread. I'd love to hear other developer's experiences, surely not everyone has created their own self-rolled GUI. I assumed Swing was the default for game developers... Cheers, Keith
|
|
|
|
DaveLloyd
Junior Member  
Making things happen fast with Java!
|
 |
«
Reply #11 - Posted
2006-04-11 15:35:22 » |
|
For my Swing menus I have only had deadlocks a couple of times, but the JTextFields I use reliably cause AWT Event thread deadlocks when I type or delete characters. What kind of Swing components are you using in your game? Maybe it only works because you use simple components which rarely cause a dead-lock with your game thread.
I think I'm using virtually every Swing component known somewhere or other! Not everything works quite as expected (JOptionPane is a big no-no) but mostly it does. All my painting etc is done ultimately under the JOGL display () method which I suspect is in fact on the EDT.
|
|
|
|
Jeff
|
 |
«
Reply #12 - Posted
2006-04-11 20:41:24 » |
|
Given that MIke Martak, the author, was part of the AWT team at the time he wrote that article. Id personally trust him unless you find later stuff thats epcificly says this as broken. Keep in mind that full-screen exclusive mode is an esoteric thing that very few people whow rite abotu Swing even know exists. For my Swing menus I have only had deadlocks a couple of times, but the JTextFields I use reliably cause AWT Event thread deadlocks when I type or delete characters.
How are you using them? Id like to see the code as Im having trouble even iomaging a multi-trheaded access case to the model..
|
|
|
|
Ask_Hjorth_Larsen
Junior Member  
Java games rock!
|
 |
«
Reply #13 - Posted
2006-04-12 03:11:30 » |
|
If pressing a button or doing anything with the mouse - which all happens from the EDT *UNLESS* lots of work is done to requeue all the stuff to the game thread in every mouse listener and... jeez I'm dizzy now - affects the game state, and if on the other hand the game state might affect the model of a swing component (say, a thing dies and is removed from a list) then we have two threads accessing the model of a swing component. I am surprised that this isn't a common problem, which is why I made a thread (org.javagaming.Thread, not java.lang.Thread  ) about it a while ago, and it basically seemed that no one uses swing components for their games. I for one don't want to write my own version of JTree so I use the approach mentioned by me above (SwingUtils.invokeAndWait to ensure logic update and active rendering from the EDT). Really, it's the only solution I can imagine!
|
|
|
|
|
fletchergames
|
 |
«
Reply #14 - Posted
2006-04-12 03:49:12 » |
|
I use Swing Components in direct-rendering games as well. In fact, I set up one Component for the whole screen that everything gets drawn to. I use regular Components as well. Dialogs are the only things that don't seem to work. I also have a NullRepaintManager and used setIgnoreRepaint to true. Here's my code that actually draws the Components to the screen: 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
| public void showFrame() { BufferStrategy bufferStrategy = mainFrame.getBufferStrategy(); Graphics g = bufferStrategy.getDrawGraphics();
if(!(g instanceof Graphics2D)) { ErrorLog.output( ErrorList.applicationGameFrameGraphics2DUnavailableInShowScreen); System.exit(0); } final Graphics2D g2 = (Graphics2D)g; g2.setRenderingHints(renderingHints); Insets insets = mainFrame.getInsets(); g2.setTransform(AffineTransform.getTranslateInstance(insets.left, insets.top));
final JLayeredPane layeredPane = mainFrame.getLayeredPane(); try { if(EventQueue.isDispatchThread()) layeredPane.paintComponents(g2); else { EventQueue.invokeAndWait(new Runnable() { public void run() {layeredPane.paintComponents(g2);} }); } } catch(Exception exception) { ErrorLog.output(exception, ErrorList.applicationGameFrameErrorPaintingComponents); }
Toolkit.getDefaultToolkit().sync();
g.dispose(); bufferStrategy.show(); }
|
I doubt the code will help you because you're already doing the same thing. But I posted it anyways. It was originally inspired by similar code from a book called "Developing Games in Java". My code's "better" than the code in the book, but it's the same general idea.
|
|
|
|
|
CommanderKeith
|
 |
«
Reply #15 - Posted
2006-04-12 05:06:41 » |
|
Thanks everyone for the help. I am surprised that this isn't a common problem Me too. I tried to make a test case that produced the same problem but it's working fine >> not deadlocking which I couldn't understand. But now I realize that in my game the JTextField is in a movable JInternalFrame whilst in the test case it isn't. Perhaps I'm having the same trouble as fletchergames since JInternalFrames are probably similar to Dialogs- "Dialogs are the only things that don't seem to work". How are you using them? Id like to see the code as Im having trouble even iomaging a multi-trheaded access case to the model..
I'll post the test case when I get home and have tried it with the JInternalFrame. Basically I create a frame and put compnents in it and just continuously paint them in the main thread. I manipulate the components with the mouse & keyboard (and this happens in the EDT which must sometimes conflict with the main thread, but doesn't for my current test case....) It was originally inspired by similar code from a book called "Developing Games in Java".
Yes! By David Brackeen, that's the book where I got the code from. Thanks for posting your code. The interesting thing about what you do is that you paint your Swing components in the EDT (through invokeAndWait) onto the BufferStrategy and then you show the BufferStrategy in your own thread. So you're kind of using a weird combination of passive and active rendering. This should have the same draw back pointed out by Jeff earlier that (part of) the painting is done in the EDT - so your screen paints may come late while you wait for the EDT to do the job - not really direct/active rendering. Since all of you - Dave, fletchergames and Ask_Hjorth_Larsen seem to only be having success with painting from the EDT then perhaps Swing cannot be used for non-JOGL direct-rendering games. But I'll look deeper into my test case (which is working, strangely enough) and I'll post the code ASAP. Keith
|
|
|
|
CommanderKeith
|
 |
«
Reply #16 - Posted
2006-04-12 08:21:08 » |
|
From - http://www.clientjava.com/blog/2004/08/24/1093363375000.html"The single-thread rule (from the Java Tutorial) Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread. ... Realized means that the component's paint() method has been or might be called. A Swing component that's a top-level window is realized by having one of these methods invoked on it: setVisible(true), show(), or (this might surprise you) pack()." Since painting depends on the state of the component then painting from outside the Event Dispatch Thread (EDT) must not be thread-safe. Is this reasoning correct because it makes Swing useless for active-rendering and also contradicts what Jeff said in an earlier post. Thanks, Keith PS: Keep in mind that full-screen exclusive mode is an esoteric thing that very few people who write about Swing even know exists.
I only mentioned the full screen mode tutorial because it prescribes calling setIgnoreRepaint() on components. I am not actuallly using full screen mode when doing direct-rendering with Swing.
|
|
|
|
Jeff
|
 |
«
Reply #17 - Posted
2006-04-12 23:59:07 » |
|
If pressing a button or doing anything with the mouse - which all happens from the EDT *UNLESS* lots of work is done to requeue all the stuff to the game thread in every mouse listener
Right. hats one thread. Where is the other one? Its that which im having a hard time imgining.
|
|
|
|
Jeff
|
 |
«
Reply #18 - Posted
2006-04-13 00:08:03 » |
|
From - http://www.clientjava.com/blog/2004/08/24/1093363375000.html"The single-thread rule (from the Java Tutorial) Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread. ... Realized means that the component's paint() method has been or might be called. No. In that context it means it has been ro might be called BY THE AWT PAINT tHREAD. The problem with all these things you keep quoting is that they are ALL written with the asusmption that you are doing normal AWT/Swing repainting, *not* active rendering. I'm not saying your wrong, because I don't know those internals, but I think its more likely you are then you arent. I DO knwo that all these articles are orthogonal to the issue. This is because the ONLY source on this option and what it really does under the hood is Mike Martak, who is no longer with us and thus cannot comment. Given that, I take his writings, which DO address manual painting, as definitive. Question: have you gotten rid of all the WEIRD sh-t you were doing? I read in a book somewhere that you can stop the AWT Event dispatching thread from painting by installing a 'NullRepaintManager', a class you make as a sub-class of RepaintManager that over-rides:
public void addInvalidComponent(JComponent c) public void markComponentDirty(JComponent c) public void addDirtyRegion(JComponent c) public void paintDirtyRegions()
with empty method bodies. You install it as follows::
RepaintManager rm = new NullRepaintManager(); rm.setDoubleBufferingEnabled(false); RepaintManager.setCurrentManager(rm);
If not thats far more likely to be the cause of your problems. Thats all I have to give on this subject and Im repeatign myself so I'll stop here.
|
|
|
|
CommanderKeith
|
 |
«
Reply #19 - Posted
2006-04-13 07:19:11 » |
|
Test case that deadlocks: import java.awt.*; import javax.swing.*; import java.awt.image.*; import java.awt.geom.*;
public class SwingDirectRendering extends JFrame{
public JPanel content; public JTextField textField;
public SwingDirectRendering(){ super("SwingDirectRendering Test");
setIgnoreRepaint(true); // disable OS-triggered repaint requests RepaintManager.currentManager(this).setDoubleBufferingEnabled(false); // disable double-buffering since we do this in the BufferStrategy
content = new JPanel(new BorderLayout()); setContentPane(content);
textField = new JTextField("Type & delete stuff here", 50);
JPanel panel = new JPanel(new BorderLayout()); panel.add(textField); content.add(panel); //content.add(textField); // comment out the above 3 lines and // uncomment this and it will work - // there will be no deadlock
setUndecorated(true); setDefaultCloseOperation(EXIT_ON_CLOSE); setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
createBufferStrategy(2); }
public static void main(String[] arrghImAPirate){ SwingDirectRendering frame = new SwingDirectRendering();
while (true){ Graphics g = frame.getBufferStrategy().getDrawGraphics();
//Graphics g = frame.content.getGraphics() // to show that its not a BufferStrategy // problem you can uncomment the above and leave // out the BufferStrategy code
frame.content.paintComponents(g); frame.getBufferStrategy().show(); } } }I've found that component.paintComponent(Graphics) works when its children have no child components themselves. When its child components have their own child components then deadlock results. You can see this by commenting out the intermediate JPanel that sits between the content pane and the JTextField. Help appreciated  , Keith
|
|
|
|
CommanderKeith
|
 |
«
Reply #20 - Posted
2006-04-13 16:47:23 » |
|
I said I'd tell how my experiences with Swing panned out, so...
I've read a lot about how GUIs work, including the SWT (IBM's alternative to AWT/Swing) and as far as I can see (not very), Swing is fundamentally flawed for use in direct-rendering games since it is so closely tied to the AWT Event Dispatch Thread (EDT). As Ask_Hjorth_Larsen said it looks like the only thread-safe way Swing can be used is to have the whole game running in the EDT which won't work.
The SWT (Standard Widget Toolkit) would work in direct-rendering games since there is no EDT, all communication with the Operating System for events and painting is done through the main thread. But I've decided not to use the SWT because its not completely flexible & portable due to the way SWT components are all backed by their native/heavyweight OS equivalents.
I've decided to go with my own crappy GUI system because at least it works and I know what it's doing.
I'd love to know if anybody has used Swing successfully without doing EventQueue.invokeAndWait() etc, but unless I've stuffed up something obvious, the above example shows how Swing can't be used in a direct-rendering game.
Keith
|
|
|
|
Luke
Senior Newbie 
I love YaBB 1G - SP1!
|
 |
«
Reply #21 - Posted
2006-04-13 17:40:26 » |
|
I think the problem is that the AWT event thread is accessing your swing components at the same time that you are drawing them from another thread. I have had the same problem and the following solution worked for me. Add the following class.. 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
| import java.awt.AWTEvent; import java.awt.EventQueue; import java.awt.Toolkit;
final public class SynchronizedEventQueue extends EventQueue { public static final Object MUTEX = new Object();
private static final SynchronizedEventQueue instance = new SynchronizedEventQueue();
private static boolean alreadyInUse = false;
private SynchronizedEventQueue() { }
public static synchronized void use() { if (!alreadyInUse) { EventQueue eventQueue = Toolkit.getDefaultToolkit() .getSystemEventQueue(); eventQueue.push(instance); alreadyInUse = true; } }
protected void dispatchEvent(AWTEvent aEvent) { synchronized (MUTEX) { try { super.dispatchEvent(aEvent); } catch (Exception e) { } } } } |
then change your game loop to... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public static void main(String[] arrghImAPirate) { SwingDirectRendering frame = new SwingDirectRendering(); SynchronizedEventQueue.use(); while (true) { synchronized (SynchronizedEventQueue.MUTEX) {
Graphics g = frame.getBufferStrategy().getDrawGraphics();
frame.content.paintComponents(g); frame.getBufferStrategy().show(); } } } |
On my machine it seems to solve the deadlock problem. Hope it helps Luke
|
|
|
|
|
CommanderKeith
|
 |
«
Reply #22 - Posted
2006-04-13 18:41:48 » |
|
100% Sensational!  Luke you are a legend, that peice of code is a silver bullet! Not only is it kicking ass in the test case but I just tried it in my game and it works perfect! I thought that the synchronized block would sap performance but no, the frame rate doesn't change whether or not I use the SynchronizedEventQueue. That's a very elegant solution. Being able to use Swing in my menus will make life a lot easier  . By the way, what is the cost (if any) of sync'ing these events? Speed? Mouse & keyboard responsiveness? In the test case how much of the game loop needs to be synchronized? To reduce cost of sync'ing, could you safely change it to this since much time is taken blitting from the bufferStrategy to the screen compared with painting to the bufferStrategy: while (true) { Graphics g = frame.getBufferStrategy().getDrawGraphics(); synchronized (SynchronizedEventQueue.MUTEX) { frame.content.paintComponents(g); } frame.getBufferStrategy().show(); } } Many thanks, Keith
|
|
|
|
fletchergames
|
 |
«
Reply #23 - Posted
2006-04-15 20:14:49 » |
|
I think the problem is that the AWT event thread is accessing your swing components at the same time that you are drawing them from another thread. I have had the same problem and the following solution worked for me.
...
Wow, I never thought of trying anything like that before. When I get a chance, I'll try doing something similar in my code to see what happens. Thanks for the idea.
|
|
|
|
|
Ask_Hjorth_Larsen
Junior Member  
Java games rock!
|
 |
«
Reply #24 - Posted
2006-04-16 19:15:51 » |
|
Whoa, whoa, wait a minute. It's possible to use active rendering within the EDT unless I have completely misunderstood the concept. Rendering is not magically active or passive as determined by which thread it runs from. The repaint() system, which queues and collapses calls and so on is passive rendering. If you perform the rendering immediately when desired, as opposed to queueing and collapsing, then it is active rendering. If this is correct (which is not trivial because the invokeAndWait method which I'm going to suggest may involve some EDT queueing along with peripheral input and so on, though no repaint management takes place), then the invokeAndWait method can easily be used to render actively from the EDT. I assume the invokeAndWait is sufficiently efficient (i.e. that the passive rendering overhead which we hate is incurred mostly by the paint management and thus not the queueing itself). Jeff said: Right. hats one thread.
Where is the other one?
Its that which im having a hard time imgining. It's the main Thread of the game, which is used for the main loop. That's not the EDT, so it *is* another Thread. So basically the user fiddles with the mouse and the corresponding stuff happens in some actionPerformed or mouseMoved method from the EDT. Perhaps the user action causes the window to scroll. Now, it's a pain in the lower back to queue this event and execute it from the main thread instead of the EDT. So if it's executed from the EDT then the window scrolls while the main thread is likely busy painting, possibly resulting in tearing because - well - perspective changes while the screen is updated. I hope this was clear.
|
|
|
|
|
Mr_Light
|
 |
«
Reply #25 - Posted
2006-04-16 19:42:19 » |
|
the difference between passive and active is that passive is wenn it's told to/wenn it's needed vs active which is all the time.
the whole deathlock issue has to do with swing not beeing thread save. and has inheritely nothing todo with the whole active of passive rendering. It's the way we achive active rendering that causes the issues.
|
It's harder to read code than to write it. - it's even harder to write readable code.
The gospel of brother Riven: "The guarantee that all bugs are in *your* code is worth gold." Amen brother a-m-e-n.
|
|
|
fletchergames
|
 |
«
Reply #26 - Posted
2006-04-17 04:24:37 » |
|
I tried Luke's code. Since I was using active rendering before (yes, from within the EDT), that wasn't really the issue. I was hoping for a performance gain. It turns out that frame rate is, on average, the same.
It may end my problem with dialogs being displayed oddly, but I'm not really concerned with that as I wrote my own almost-a-dialog class almost a year ago.
I also tried removing the NullRepaintManager code (which came from Developing Games in Java). There was no performance gain, but I was getting periodic NullExceptions for some reason. I was already randomly getting NullExceptions at start up once I started using Java 6 beta. But the NullExceptions were caught and had no effect except to add text to the error log. Since I then suspected that the problem was somehow solved by NullRepaintManager, I moved the NullRepaintManager to occur earlier in the code. Now there are no more NullExceptions at all.
I think the issue is that the regular Java RepaintManager was trying to draw Components that weren't completely initialized after I went into full-screen exclusive mode but before I installed the NullRepaintManager. I could probably do away with the NullRepaintManager altogether if I made sure that Components weren't made visible before their time, but it's easier just to keep the NullRepaintManager.
|
|
|
|
|
nanobomber
Junior Newbie
|
 |
«
Reply #27 - Posted
2006-04-21 00:05:52 » |
|
Hi, I was reading your postings since I wanted to use Swing as data input framework for my game so that I don't need to develop one of my own. Here I send you a little test program which open a dialog for text input and it seems to work OK. Don't know if it represent the kind of problems you have with your rendering code. I followed the active rendering examples from the book Killer Game Programming it seems to be deadlock free (can't assure it though). The problem I found with this is that it seems to me that the code is somewhat slow and the cube doesn't get rendered solid but I shows some flickering. So I post the code to see if anyone has a better idea of why those things are happening. Regards, Gabriel 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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
| import java.awt.*; import java.awt.event.*; import javax.swing.*;
import com.sun.j3d.utils.timer.*;
public class ActiveSwingTest implements Runnable {
static final int VEL = 1;
private static final int NO_DELAYS_PER_YIELD = 16;
private static int MAX_FRAME_SKIPS = 5; JFrame f; JPanel panel; Image backBuffer;
JDialog dialog;
private long gameStartTime; private long prevStatsTime; private boolean running; private Graphics2D graphics; private long period; private long framesSkipped = 0;
int x = 0; int y = 0; int vx = VEL; int vy = VEL;
public ActiveSwingTest() { initGraphics(); }
public void initGraphics() { panel = new JPanel(); panel.setPreferredSize(new Dimension(800, 600)); panel.setFocusable(true); panel.requestFocus(); panel.setIgnoreRepaint(true); readyForTermination();
f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.getContentPane().add(panel); f.setIgnoreRepaint(true);
f.setResizable(false); f.pack();
backBuffer = createBackBuffer(); if(backBuffer == null) { return; }
f.setVisible(true); }
public void run() { long timeDiff = 0; long overSleepTime = 0L; int noDelays = 0; long excess = 0L;
gameStartTime = J3DTimer.getValue(); prevStatsTime = gameStartTime; long beforeTime = gameStartTime;
running = true;
graphics = (Graphics2D) backBuffer.getGraphics();
while(running) { update(timeDiff); render(graphics);
paintScreen();
long afterTime = J3DTimer.getValue(); timeDiff = afterTime - beforeTime; long sleepTime = (period - timeDiff) - overSleepTime;
if(sleepTime > 0) { try { Thread.sleep(sleepTime / 1000000L); } catch(InterruptedException ex) {} overSleepTime = (J3DTimer.getValue() - afterTime) - sleepTime; } else { excess -= sleepTime; overSleepTime = 0L;
if(++noDelays >= NO_DELAYS_PER_YIELD) { Thread.yield(); noDelays = 0; } }
beforeTime = J3DTimer.getValue();
int skips = 0; while((excess > period) && (skips < MAX_FRAME_SKIPS)) { excess -= period; update(timeDiff); skips++; } framesSkipped += skips; }
System.exit(0); }
private void showDialogo() { if ( dialog == null ) { dialog = new JDialog(f, "Example dialog", true); final JTextField t = new JTextField("hello"); JButton bok = new JButton("OK"); bok.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("text="+t.getText()); dialog.setVisible(false); dialog.dispose(); dialog = null; } }); JButton bcancel = new JButton("Cancel"); bcancel.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dialog.setVisible(false); } });
final Container c = dialog.getContentPane(); c.setLayout(new BorderLayout()); c.add(t, BorderLayout.CENTER);
final JPanel buttonPanel = new JPanel();
buttonPanel.add(bok); buttonPanel.add(bcancel);
c.add(buttonPanel, BorderLayout.PAGE_END);
dialog.pack(); dialog.setLocationRelativeTo(f);
dialog.setVisible(true); } else { dialog.setVisible(true); } }
private void paintScreen() { try { final Graphics g = panel.getGraphics(); if(g != null) { g.drawImage(backBuffer, 0, 0, null); } g.dispose(); } catch(Exception e) { System.out.println("Graphics context error: " + e); } }
private Image createBackBuffer() { final Image dbImage = panel.createImage(800, 600); if(dbImage == null) { System.out.println("could not create the backbuffer image!"); } return dbImage; }
private void readyForTermination() { panel.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); if((keyCode == KeyEvent.VK_ESCAPE) || (keyCode == KeyEvent.VK_Q) || (keyCode == KeyEvent.VK_END) || ((keyCode == KeyEvent.VK_C) && e.isControlDown())) { running = false; } else if ( keyCode == KeyEvent.VK_D ) { showDialogo(); } } }); }
private void update(long dt) { x += vx; y += vy;
if ( x < 0 ) { x = 0; vx = VEL; } else if ( x > 700 ) { x = 700; vx = -VEL; }
if ( y < 0 ) { y = 0; vy = VEL; } else if ( y > 500 ) { y = 500; vy = -VEL; } }
private void render(Graphics2D g) { g.setColor(Color.RED); g.fillRect(0, 0, 800, 600); g.setColor(Color.WHITE); g.fillRect(x, y, 100, 100); }
public static void main(String[] args) { ActiveSwingTest test = new ActiveSwingTest(); new Thread(test).start(); }
} |
|
|
|
|
|
fletchergames
|
 |
«
Reply #28 - Posted
2006-04-24 05:13:02 » |
|
Hi,
...
The problem I found with this is that it seems to me that the code is somewhat slow and the cube doesn't get rendered solid but I shows some flickering. So I post the code to see if anyone has a better idea of why those things are happening.
...
Try using the BufferStrategy class instead of drawing to your own BufferedImage and then drawing that to the screen. BufferStrategy can use page flipping if your graphics hardware supports it. And, if if it doesn't support page flipping, I believe it can wait for the vertical retrace period (or whatever it's called) to avoid drawing to the video memory while it's being displayed to the monitor. If you don't want to do use BufferStrategy for some reason, at least try accelerating the BufferedImage using Image.setAccelerationPriority. That's a bad idea though because Image.setAccelerationPriority just suggests that image acceleration occurs. So, you should really use BufferStrategy.
|
|
|
|
|
|
|
|