How can i delete previous BufferedImages from Graphics stack in Java? - java

My problem is quite simple to understand. I have a JPanel inside a JFrame in order to display some graphics using the drawFormula() method below to display 3d points in screen using perspective projection. Everytime drawFormula() reaches its end I just recall itself to draw the shape again and again and again and because I dont want to have any image flickering problems I dont use the paintComponent method but i call drawImage() method from panelG which I get from this.getGraphics() method of my JPanel. Everything runs fine, but the problem is that after a certain amount of time it stops rendering and i believe that it has to do with the list of BufferedImages it holds everytime i call drawImage(). Is there a way to remove the previous not needed images from the stack? Thanks in advance!
public void drawFormula(){
for(double i=latMin;i<latMax;i+= 0.05){
for(double j=longMin;j<longMax;j+= 0.05){
calc(m,n1,n2,n3,i,j);
applyRotationX();
applyRotationY();
applyRotationZ();
if(outX>xxmin && outX<xxmax && outY>yymin && outY<yymax){
xxx = (int)((outX-xxmin)*xinc);
yyy = (int)((outY-yymin)*yinc);
zzz = (int)((outZ-zzmin)*zinc);
//img_g.drawRect(xxx, yyy, 1, 1);
//img_g.drawRect((int) (planeX.getOffset(new Vector3D(xxx,yyy,zzz)))+600,(int) (planeY.getOffset(new Vector3D(x[i],y[i],z[i])))+350+j,1,1);
//img_g.setColor(new Color(Color.HSBtoRGB((float)(outX/outY), (float)(outY), (float)(outZ))));
drawPoint(xxx, yyy, zzz);
//panelG.drawImage(img, 0, 0, null);
}
}
}
//panelG.dispose();
//panelG = getGraphics().create();
panelG.drawImage(img, 0, 0, null);
thetaX += 1;
thetaX %= 360;
img_g.setColor(Color.black);
img_g.fillRect(0, 0, getWidth(), getHeight());
drawFormula();
}

I think it stops rendering due to a stackoverflow. You have an unconditioned recursion in your code (the drawFormula() at the end of drawFormula), which will cause a stackoverflow at some point. For the flickering: use setDoubleBuffered(true), this should solve your problem aswell.

Related

Double buffering swt

I'm creating simple app i have Tree object where i store filenames when user choose one SWTImageCanvas.loadImage(path) is being called. Every image has some points defined so points are displayed as gc.fillOval. When user move mouse over oval it name is being displayed i achive this by setting some additional variable and using SWTImageCanvas.redraw() method. Such redrawing cause blinking of canvas so i thought about double buffering i have read some tutorials about it but when i'm trying to run it my image is hovered by white layer with ovalls on it here is my drawing function
private void drawStations(Event e) {
Rectangle clientRect = mainSWTImageCanvas.getClientArea();
if(mainSWTImageCanvas.getSourceImage()!=null)
{
if(mainSWTImageCanvas.getScreenImage()!=null)
mainSWTImageCanvas.getScreenImage().dispose();
Image screenImage = new Image(mainSWTImageCanvas.getDisplay(),clientRect.width,clientRect.height);
this.gc = new GC(screenImage);
//drawing ovals on gc
.
.
.
this.gc.drawImage(screenImage, 0, 0);
this.gc.dispose();
e.gc.drawImage(screenImage, 0, 0);
}
It turns out that double buffering in swt display can by done by passing SWT.DOUBLE_BUFFERED in constructor.

Graphics2D reset Screen?

I have a Game Tutorial that I followed, that paints String's on the Screen using Graphics2D. It works like a star, but the only problem is that I don't undertstand why.
I call draw(graphics) in a game loop and it works fine. I use an int, named currentChoice to keep track of which letter should be Red and which should be Black.
Well, I call the method Draw in a loop. I just don't understand how does the graphics clear the previous string it drew. I mean, I call the method constantly, and it keeps on Drawing string's on the window, and its 'clearing' the other ones (if you get what i'm saying).
Basicly, I just don't undertstant how it's clearing the screen (NOTE: I am super new to this sort of thing)
CODE (I call this in a loop and it works):
public void draw(Graphics2D graphics) {
bg.draw(graphics);
graphics.setColor(titleColor);
graphics.setFont(titleFont);
graphics.drawString("Peache's Revenge", 50, 70);
graphics.setFont(font);
for (int i = 0; i < options.length; i++) {
if (i == currentChoice) {
graphics.setColor(Color.RED);
} else {
graphics.setColor(Color.BLACK);
}
graphics.drawString(options[i], 145, 140 + i * 15);
}
}
Assuming the Graphics context does not change (ie is the same for each call), then, unless the background is cleared, content will continue to be painted ontop of it.
From you comments, bg.draw is drawing the background, over the top of whatever was previously painted, meaning that anything that was previously painted will now be covered by the background, thus requiring the text to be re-generated.

Why is Graphics not painting?

I searched google for this problem, but i can't really resolve them.
More info on code below.
Here are the two snippets of code, relevant:
//prepare
g = (Graphics2D) strategy.getDrawGraphics();
g.setColor(Color.white);
g.fillRect(0,0,getWidth(),getHeight());
for(ListIterator<Chunk> it = chunkvector.listIterator();it.hasNext();){
Chunk r = it.next();
r.drawChunk(g);
}
for(ListIterator<Entity> it = vectorpainter.listIterator();it.hasNext();){
Entity r = it.next();
r.drawObjects(g);
}
//Chat
if(coni.getVerified()){
try {
chat.update(g);
} catch (IOException e) {
println("I/O Exception while updating chat! "+e.toString());
}
//Framerate Anzeige
if(fps_on){
g.setColor(Color.red);
g.drawString("FPS: "+fps, 20, 20);
}
//Tickberechnung & Anzeige
tick++;
if(tick>=65536)
tick=0;
if(tick_on){
g.setColor(Color.red);
g.drawString("Tick: "+tick,80,20);
}
//end drawing
g.dispose();
strategy.show();
interesting about that:
Chunks, Entities are painted, white rect also, but fps and tick NEVER (both are true, of course), i even wrote System.out.print("..."); into the if-clauses, and it is executed! :S
I think it is something about GPU acceleration, so i added the second code block, how images are loaded. One entity does also drawString, (showing playername above head) and it works, but in the main thread not? :(
second:
public Image[] loadPics(String path, int cnt){
Image[] anim = new Image[cnt];
BufferedImage source = null;
BufferedImage temp;
URL pic_url = getClass().getResource(path);
if (pic_url == null) {
fail("Can't find ref: "+path);
}
try{
source = ImageIO.read(pic_url);
}catch(IOException e){
fail("Failed to load: "+path);
}
// create an accelerated image of the right size to store our sprite in
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
for(int x=0;x<cnt;x++){
temp = source.getSubimage(x*source.getWidth()/cnt, 0,
source.getWidth()/cnt, source.getHeight());
anim[x]= gc.createCompatibleImage(temp.getWidth(), temp.getHeight(), Transparency.BITMASK);
anim[x].getGraphics().drawImage(temp,0,0,null);
}
System.out.println(pic_url+" - loaded.");
return anim;
}
second one i copied from a tutorial, maybe a bit edited.Before that i"ve painted with paintComponent(Graphics g) ... this worked, tutorial have said i could get better performance using this method, so i tried, and want to manage it somehow.
Now it is drawing in a run loop, when i copy everything to paintComponent, no Images are drawn.
For those who managed to get past all the text a little bit of extra work:
The program runs fine on a university pc - not that good hardware ^^ , and bit of laggy at mine, which should be more than double the computationpower. Any ideas? :(
Java(c) 1.7
Many thanks, even you just read that! :)
Okay, this can be closed. My drawing problem had nothing to do with the code above.
Problem was, that things i wanted to paint were not in the picture. That I achieved through giving statements like:
fillRect(50,50,2/3*frame.getHeight(),130);
the 2/3 resolves to 0, multiplied with frameHeight...
Trick was to write (int)(2./3.*frame.getHeight())
and one time I also tried to draw a String into the panel section, where closing , maximize buttons are, that wont work too , of course.
THanks anyway!

Why does VolatileImage have no set/getPixel() method

I am a relative newbie in game programming. I know how to draw pixels to a BufferedImage using setPixel(). It is horribly slow on larger formats so I moved on and found VolatileImage (took me a week or so). It is fairly easy to draw lines, strings, rects, etc but I can't draw individual pixels. I already tried using drawLine(x,y,x,y) but I get 3-4 FPS on an 800x600 image.
The fact that java didn't include setPixel() or setRGB() in the VolatileImage makes me pretty angry and confused.
I have 4 questions:
Is there a way to draw individual pixels on a VolatileImage? (on 1440x900 formats with FPS > 40)
Can I draw pixels in a BufferedImage with a faster method? (same 1440x900, FPS > 40)
Is there any other way to draw pixels fast enough for 3D games?
Can I make my BufferedImage hardware accelerated( tried using setAccelerationPriority(1F) but it doesn't work)
Please if you have any idea tell me. I can't continue making my game wihout this information. I already made 3D rendering algorithms but i need to be able to draw fast pixels. I have got a good feeling about this game.
Here's the code if it can help you help me:
public static void drawImageRendered (int x, int y, int w, int h) { // This is just a method to test the performance
int a[] = new int[3]; // The array containing R, G and B value for each pixel
bImg = Launcher.contObj.getGraphicsConfiguration().createCompatibleImage(800, 600); // Creates a compatible image for the JPanel object i am working with (800x600)
bImg.setAccelerationPriority(1F); // I am trying to get this image accelerated
WritableRaster wr = bImg.getRaster(); // The image's writable raster
for (int i = 0; i < bImg.getWidth(); i++) {
for (int j = 0; j < bImg.getHeight(); j++) {
a[0] = i % 256;
a[2] = j % 256;
a[1] = (j * i) % 256;
wr.setPixel(i, j, a); // Sets the pixels (You get a nice pattern)
}
}
g.drawImage(bImg, x, y, w, h, null);
}
I would much prefer not using OpenGL or any other external libraries, just plain Java.
Well you're basically drawing one pixel after the other using the CPU. There's no way that this can be accelerated, thus such a method does simply not make any sense for a VolatileImage. The low FPS you get suggest that this even causes a significant overhead, as each pixel drawing operation is sent to the graphics card (with information such as location & colour), which takes longer than to modify 3 or 4 bytes of RAM.
I suggest to either stop drawing each pixel separately or to figure out a way to make your drawing algorithm run directly on the graphics card (which most likely requires another language than Java).
It's been over 4 years since this post got an answer. I was looking for an answer to this question as well and stumbled on this post. After some more searching, I got it to work. Below I'll post the source to rendering pixels with a VolatileImage.
It seems Java hides our ability to plot pixels directly to a VolatileImage, but we can draw buffered images to it. For good reason. Using the software to plot a pixel doesn't really help with acceleration(in Java it seems). If you can plot pixels to a BufferedImage, and then render it on a VolatileImage, you may get a speed bonus since it's hardware accelerated from that point.
The source down below is a self-contained example. You can copy-pasta practically all of it to your project and run it.
https://github.com/Miekpeeps/JavaSnippets-repo/blob/master/src/graphics_rendering/pixels_03/PlottingVolatile.java
In the constructor I save the Graphics environment of the app/game.
private GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
private GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
Then, when I call a method to enable hardware we create a buffer. I set the transparency to Opaque. In my little engine, I deal with transparency/alpha blending on another thread in the pipeline.
public void setHardwareAcceleration(Boolean hw)
{
useHW = hw;
if (hw)
{
vbuffer = gc.createCompatibleVolatileImage(width, height, Transparency.OPAQUE);
System.setProperty("sun.java2d.opengl", hw.toString()); // may not be needed.
}
}
For each frame I update, I get the Graphics from the VolatileImage and render my buffer there. Nothing gets rendered if I dont flush().
#Override
public void paintComponent(Graphics g)
{
if(useHW)
{
g = vbuffer.getGraphics();
g.drawImage(buffer, 0, 0, null);
vbuffer.flush();
}
else
{
g.drawImage(buffer, 0, 0, null);
buffer.flush();
}
}
There is still a little bit of overhead when calling to plot a pixel on the BufferedImage writable raster. But when we update the screen, we get a speed boost when using the Volatile image instead of using the Buffered image.
Hope this helps some folks out. Cheers.

java - why does graphics.drawString() not redraw?

this is beyond me (be forgiving, it's late). I'm subclassing a WindowsSliderUI, because I want it to draw a bigger thumb (is that the right word?)(that's working) and also display the value of the slider just above it (like, for example, gtk look and feel does)(that's broken). I'm overriding the paint() method, and at the moment it looks like this: (it's long, my changes are near the bottom):
Rectangle knobBounds = thumbRect;
int w = knobBounds.width;
int h = knobBounds.height;
g.translate(knobBounds.x, knobBounds.y);
if ( slider.isEnabled() ) {
g.setColor(slider.getBackground());
}
else {
g.setColor(slider.getBackground().darker());
}
Boolean paintThumbArrowShape =
(Boolean)slider.getClientProperty("Slider.paintThumbArrowShape");
if ((!slider.getPaintTicks() && paintThumbArrowShape == null) ||
paintThumbArrowShape == Boolean.FALSE) {
// "plain" version
g.fillRect(0, 0, w, h);
//THE ONES THAT MATTER
g.setColor(Color.BLACK);
String val = slider.getValue()+"";
g.drawString(val, 0, 0);
g.setColor(Color.RED);
g.drawLine(0, 0, 30, 8);
//END
g.setColor(Color.black);
g.drawLine(0, h-1, w-1, h-1);
g.drawLine(w-1, 0, w-1, h-1);
g.setColor(getHighlightColor());
g.drawLine(0, 0, 0, h-2);
g.drawLine(1, 0, w-2, 0);
g.setColor(getShadowColor());
g.drawLine(1, h-2, w-2, h-2);
g.drawLine(w-2, 1, w-2, h-3);
}
all i want is to get the value displayed just above the thumb. however, what happens now is the string gets displayed initially, but when i drag the slider, it stays in the same place (not changing value) until i release the mouse button, at which point it is redrawn at the right place with the right value. and just to make my head go even funnier, the drawLine() method works fine - the line is always on the thumb when i drag it.
now, this is probably trivial mistake (i'm really no good, and tired), but please help me find it. mind you, if you see a better approach to the whole problem, let me know as well. as i said, i'm really no good with this, and i tend to make things more complicated than they are.
thanks a lot
I don't know the complete answer, but your call to
g.drawString(val, 0, 0);
looks dodgy. The co-ordinates you specify to drawString are the baseline of the leftmost character in the string, not the top-left hand corner of the string. Typically a call like yours results in nothing appearing, because all or most of the string is drawn outside of the clipping rectangle.
Perhaps you meant something like this:
final int height = g.getFontMetrics().getAscent();
g.drawString(s, 0, height);

Categories