Im building a blackjack game in java for school and I can't seem to figure out how to add the first four cards to the GPanel. The array of cards are shuffled and the strings in the array match the file name of the images. I can get the first card in the array to load but not the other three. Any help would be awesome.
public void paintComponent(Graphics g) {
//System.out.println(gameInProgress);
if(gameInProgress == true) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Image image = null;
int i;
currentPosition = 0;
for (i = 0; i < 4; i++) {
image = Toolkit.getDefaultToolkit().getImage("images/"+deck[currentPosition - i]+".png");
currentPosition++;
}
g2.drawImage(image, 115, 5, 80, (int) 106.67, this);
g2.finalize();
}
}
You have 3 main issues in your code.
The first issue is caused by [currentPosition - i] because the result will always equal 0, so the image/card at array index 0 will be the only one that will ever be drawn.
The second issue is that you only draw one image because g2.drawImage is only called after the for loop, instead it should be inside the for loop so that all 4 images/cards are drawn.
The third issue is that you always draw your images in the same place, so even if you where drawing all 4 images you would only see the last one because it covers the previous ones.
Try this, it should print all 4 images (Assuming you have a 435x112 panel):
public void paintComponent(Graphics g) {
//System.out.println(gameInProgress);
if(gameInProgress == true) {
super.paintComponent(g);
//Add a couple new variables
int x = 115;
Graphics2D g2 = (Graphics2D) g;
Image image = null;
int i;
for (i = 0; i < 4; i++) {
image = Toolkit.getDefaultToolkit().getImage("images/"+deck[i]+".png");
//New location of g2.drawImage
//The X positions should change each time
g2.drawImage(image, x, 5, 80, 107, this);
//Change the X location of the next image
x = x + 80;
}
//Moved g2.drawImage from here to above the bracket
g2.finalize();
}
}
Related
I have a large set of data I wish to plot on a graph that can range from 10k points to about 20 Million Points. At 10k points the plot happens at an ok speed(within a second), but at 20 Million points the plot seems to take minutes.
I'm using Java for the program and rewriting the code in another language just to improve the graphical plotting speed for one single plot that only occurs at at maximum data set is not in the cards.
Is this speed something I have to live with because a 20 Million point plot inherently will take this long due to the data size or am I missing out on some optimisation flag/method/etc?
My Data is in a 2d Array of 13,000 by 4096 called Data.
This is populated from outside the Plot Function in Main.java
//In Plot.java
public class PlotG extends JPanel
{
double xscale = 0.0;
double yscale = 0.0;
protected void paintComponent(Graphics g)
{
super.paintCompnent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHint.Key_ANTIALIASING, RenderingHint.VALUE_ANTIALIAS_ON);
//Scaling
int sizew = Data.size();
int sizeh = Data.get(0).size();
xscale = (getWidth()*1.0)/(sizew *1.0);
yscale = (getHeight()*1.0)/(sizeh *1.0);
//Set Colour
g2.setPaint(Color.GREEN);
//Plot
for(int j=0; j<sizew; j++)
{
for(int k=0;k<sizeh; k++)
{
if(Data.get(j).get(k) > MinimumValueToPlot) //I only plot points above the constant value MinimumValueToPlot
{
int x = xscale*j;
int y = yscale*k;
g2.fillOval(x,y,1,1);
}
}
}
return;
}
}
private Plot dataPlot = new Plot()
public PlotStuff(ArrayList<ArrayList<Double>> In)
{
Data = In;
InitPLot(getContentPane());
}
private void InitPlot(Container contentPane)
{
getContentPane().setBackground(Color.GRAY);
getContentPane().setLayout(new FlowLayout(FlowLayout.LEADING));
setMinimumSize(new Dimension(1650, 830));
pack();
GraphPanel = new JPanel();
GraphPanel.setBounds(6,11,1470,750);
GraphPanel.setBorder( BorderFactory.createTitleBorder( BorderFactory.createLineBorder(Color.GREEN, 2),
"Title",
TitledBorder.DEFAULT_JUSTIFICATION,
TitledBorder.DEFAULT_POSITION,
new Font("Tahoma", Font.BOLD, 18),
Color.WHITE));
getContentPanel().add(GraphPanel);
GraphPanel.setLayout(new BorderLayout());
dataPlot.setBackGround(Color.BLUE);
dataPlot.setForeGround(Color.WHITE);
dataPlot.setPreferredSize(new Dimension(1470, 750));
GraphPanel.add(dataPlot);
return;
}
//in Main.java
.
.
PlotStuff p = new PlotStuff(Data);
p.redrawGraph();
p.setVisible();
.
.
Is there anyway to improve the speed if the number of points above my constant MinimumValueToPlot reaches 20 Million and above? Given my maximum possible data set is 13k x 4096 = 53,248,000, it is possible, but the highest experienced number of points above MinimumValueToPlot is so far only 20 Million.
Am I doing something wrong in the JPanel declarations? I have seen some discussions say that setPreferredSize shouldn't be used? Is this the case?
Thanks.
You claim Data is a 2d array, but it is not. It is an ArrayList of ArrayLists. Work with an actual array instead.
Instead of ArrayList<ArrayList<Double>> you'd do double[][].
In your loop you are calling fillOval to set the color of a single pixel. That causes huge unneccessary overhead. You are basically telling your application to calculate the pixels for an oval shape of size 1x1 20 million times!
I suggest you create a BufferedImage, get its pixel array, and set the pixel values directly. Then, when done, draw that image to your Graphics2d object:
BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D imgGraphics2D = img.createGraphics();
imgGraphics2D.setColor(Color.white);
imgGraphics2D.fillRect(0, 0, getWidth(), getHeight());
imgGraphics2D.dispose();
byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
for(int j=0; j < sizew; j++)
{
for(int k=0; k < sizeh; k++)
{
if(data[j][k] > minimumValueToPlot)
{
int x = (int)(xscale * j);
int y = (int)(yscale * k);
int pixelindex = (y * getWidth() + x) * 3;
pixels[pixelindex + 1] = 255; // set the green byte
}
}
}
g2.setComposite(AlphaComposite.Src);
g2.drawImage(img, 0, 0, null);
Please take this with a grain of salt, as I wrote this from memory.
(Also I took the liberty of renaming Data to data and MinimumValueToPlot to minimumValueToPlot. Per convention variables in Java start with a lower case letter to distinguish them from classes.)
Plotting points like that in your paint components means that you paint that many points every time the component is repainted This means it is an expensive operation to resize the window, or click a button because it has to repaint every point.
In this version, I've made a method to redo the graphics, and and the paintComponent just repaints the backing buffer. Note, that painting to the backing buffer will be about as fast as you can accomplish paint, and it ignores the display properties of swing. That way you can use a profiler and see how fast you can make the painting routine go. For example using some of the suggestions of Max above.
public class PlotG extends JPanel
{
BufferedImage buffer;
double xscale = 0.0;
double yscale = 0.0;
public PlotG(){
buffer = new BufferedImage(1470, 750, BufferedImage.TYPE_INT_ARGB);
}
protected void paintComponent(Graphics g)
{
super.paintCompnent(g);
g.drawImage(buffer, 0, 0, this);
}
void updateBuffer(){
Graphics2D g2 = (Graphics2D)backing.getGraphics();
g2.setRenderingHint(RenderingHint.Key_ANTIALIASING, RenderingHint.VALUE_ANTIALIAS_ON);
//Scaling
int sizew = Data.size();
int sizeh = Data.get(0).size();
xscale = (getWidth()*1.0)/(sizew *1.0);
yscale = (getHeight()*1.0)/(sizeh *1.0);
//Set Colour
g2.setPaint(Color.GREEN);
//Plot
for(int j=0; j<sizew; j++)
{
for(int k=0;k<sizeh; k++)
{
if(Data.get(j).get(k) > MinimumValueToPlot) //I only plot points above the constant value MinimumValueToPlot
{
int x = xscale*j;
int y = yscale*k;
g2.fillOval(x,y,1,1);
}
}
}
repaint();
}
public Dimension getPreferredSize(){
return new Dimension(buffer.getWidth(this), buffer.getHeight(this));
}
}
The problem with setPreferredSize, is not a performance issue, it can conflict with swings swings layout managers. When you have a component, such as your custom graphing panel, you do want to have it determine the size. I've added it to the PlotG class, so now it will try to layout according to the backing buffer.
The you have to update the buffer, I suggest doing it on the main thread after you've set your panel to visible. That way it won't block the edt.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am making a star using a draw line. I want to run a for loop to expand a star into multiple stars in a grid-like pattern. I am fairly new to java and could use some help with my code. The gride pattern that I would like the stars to open up too isn't too specific as far as columns x rows go. even making 6 stars or 9 stars is fine, as long as they are in a grid-like pattern.
So far, I have the star drawn with drawLine. At one point I got two stars but they were to close to each other. When I run the code it looks like I have a whole bunch of stars sort of staggered on top of each other and being able to get two stars on Star Field, I would like to get more in such 5x6 pattern or something close. I believe I might be having a hard time computing the math in the for loops to get this to happen.
Should I run, multiple nested for loops or is there a way to do this with using a minimal amount of for loops?
public static void drawFlag(int stars, int stripes, java.awt.Graphics
g, int x, int y, int width, int height) {
// Sets backround rectangle color to white
g.setColor(Color.WHITE);
g.fillRect(x, y, width, height);
// Draw filled red rectangles *stripes*
int stripeHeight = height/stripes;
g.setColor(Color.RED);
int lastStripeDrawnY = 0;
// For loop runs red stripes
for (int i = y; i < y + height - 2*stripeHeight; i = i + 2*stripeHeight)
{
g.fillRect(x, i, width, stripeHeight);
lastStripeDrawnY = i;
}
// expands strips across the rectangle
int lastStripeY = lastStripeDrawnY+2*stripeHeight;
int lastStripeHeight = y + height - lastStripeY;
if (stripes%2 != 0) {
g.fillRect(x, lastStripeY, width, lastStripeHeight);
}
int stars1 = 15;
for (int cols = 1; cols <= stars1; cols++) {
int rows = stars1/cols;
if (cols > rows && cols <2*rows && cols*rows == stars1) {
}
}
// Draws the starField
int numberOfRedStripes = (int)Math.ceil(stripes/2.0);
int starFieldHeight = numberOfRedStripes*stripeHeight;
int starFieldWidth = starFieldHeight*width/height;
g.setColor(Color.BLUE);
g.fillRect(x, y, starFieldWidth, starFieldHeight);
for (int x1 = 0; x1+100 <+ starFieldWidth-5; x1++) {
if(x1/5*4 == stars) {
drawStar(g,x1,y,50);
for(int y1 = 0; y1 <=starFieldHeight-5;y1++) {
if(y1/4*2 == stars) {
drawStar(g,x,y1,50);
}
}
}
}
}
// drawLine the star
public static void drawStar(java.awt.Graphics g, int x, int y, int size)
{
g.setColor(Color.WHITE);
g.drawLine(x+size/2, y+size/6, x+4*size/5, y+5*size/6);
g.drawLine(x+4*size/5,y+5*size/6, x+size/6, y+2*size/5);
g.drawLine(x+size/6, y+2*size/5, x+5*size/6, y+2*size/5);
g.drawLine(x+5*size/6, y+2*size/5, x+size/5, y+5*size/6);
g.drawLine(x+size/5, y+5*size/6, x+size/2, y+size/6);
}
}
Expand one star into a checkered grid-like pattern.
There are a number of ways you can approach this problem, you can, as you've started, simply try and build each star individually based on the required x/y position.
You could make a single star that was always at 0x0 and translate the Graphics context to the desire x/y position
Or, you could take advantage of the Shape API.
This allows you to define a self contained object which describes the shape you are trying to create.
public class StarShape extends Path2D.Double {
public StarShape(double size) {
double mid = size / 2d;
moveTo(mid, 0);
lineTo((size * 0.6d), (size * 0.4d));
lineTo(size, (size * 0.4d));
lineTo((size * 0.72d), (size * 0.58d));
lineTo((size * 0.85d), size);
lineTo((size * 0.5d), (size * 0.72d));
lineTo((size * 0.2), size);
lineTo((size * 0.325d), (size * 0.58d));
lineTo(0, (size * 0.4d));
lineTo((size * 0.4d), (size * 0.4d));
closePath();
}
}
There are lots of side benefits to this, but the immediate benefit is that it's "paintable". You can pass an instance of it directly to Graphics2D and have it painted and/or filled based on your needs.
Now, with that in hand, you can do something like...
public class TestPane extends JPanel {
private StarShape star;
private double starSize = 10;;
public TestPane() {
star = new StarShape(starSize);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double y = 0;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
double x = 0;
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
PathIterator path = star.getPathIterator(at);
GeneralPath p = new GeneralPath();
p.append(path, true);
g2d.fill(p);
x += starSize;
}
y += starSize;
}
g2d.dispose();
}
}
The reason I'd prefer this method, is it doesn't affect the origin of the original starShape. You could also use the technique to cache the results, so you're not repeatedly doing it in the paintComponent method.
You could also do something like...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double y = 0;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
double x = 0;
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
Graphics2D starg = (Graphics2D) g2d.create();
starg.translate(x, y);
starg.fill(star);
starg.dispose();
x += starSize;
}
y += starSize;
}
g2d.dispose();
}
Which changes the origin of the Graphics context instead or something like...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double xCount = getWidth() / starSize;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
g2d.fill(star);
star.transform(AffineTransform.getTranslateInstance(starSize, 0));
}
star.transform(AffineTransform.getTranslateInstance(-(starSize) * xCount, starSize));
}
g2d.dispose();
}
which changes the origin of the star itself.
Personally, I prefer not to affect the original and instead simply change the context in how it's painted, but which method you use will come down to your needs.
Okay, that might seem like a lot of work for little gain, but the Shapes API is extremely powerful. Because it's point based (instead of pixel based), it can be more easily resized, without generating pixilation. It's very simple to rotate, through the use of AffineTransform and makes for a much simpler point of re-use.
Want to make the stars bigger? Simply change starStar, for example...
private double starSize = 50;
and the API takes care of the rest...
I used your drawStar() function and built this StarPanel. Try it and see if it gives you some hints for what you are trying to achieve.
Note that I removed g.setColor(Color.WHITE); line from your drawStar() function. We need to be careful when we set color of Graphics object. In many cases, this is the reason why we don't see what we draw.
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
public class StarPanel extends JPanel
{
private int xStarting;
private int yStarting;
private int numberOfRows;
private int numberOfColumns;
private int xDisplacement;
private int yDisplacement;
public StarPanel(int xStarting, int yStarting,
int numberOfRows, int numberOfColumns,
int xDisplacement, int yDisplacement)
{
this.xStarting = xStarting;
this.yStarting = yStarting;
this.numberOfRows = numberOfRows;
this.numberOfColumns = numberOfColumns;
this.xDisplacement = xDisplacement;
this.yDisplacement = yDisplacement;
}
public static void main(String[] args)
{
StarPanel starPanel = new StarPanel(50, 50, 5, 6, 75, 75);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(starPanel);
frame.setBounds(300, 200, 500, 600);
frame.setVisible(true);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for (int row = 0; row < numberOfRows; row++) {
for (int column = 0; column < numberOfColumns; column++) {
drawStar(g, xStarting + (row * xDisplacement), yStarting + (column * yDisplacement), 50);
}
}
}
// drawLine the star
public static void drawStar(java.awt.Graphics g, int x, int y, int size)
{
g.drawLine(x+size/2, y+size/6, x+4*size/5, y+5*size/6);
g.drawLine(x+4*size/5,y+5*size/6, x+size/6, y+2*size/5);
g.drawLine(x+size/6, y+2*size/5, x+5*size/6, y+2*size/5);
g.drawLine(x+5*size/6, y+2*size/5, x+size/5, y+5*size/6);
g.drawLine(x+size/5, y+5*size/6, x+size/2, y+size/6);
}
}
I am attempting to draw the US flag using java. I have pretty much done all this coding using lots of variables. It should be at least displaying the stripes, blue box, and the stars(ovals in this case). However, when I run the code through the compiler, and run it, all it displayes is a white background with a red stripe on the top. Could I please receive some help to see where my error is? I have tried everything.
Here is the code:
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Color;
public class UsFlag extends JPanel {
int w = getWidth();
int h = getHeight();
int numberStripes = 13;
int numStarCol = 8;
int numStarRow = 6;
int stripeHeight = h/numberStripes;
int boxWidth = (int)(w*0.4);
int boxHeight = 7 * stripeHeight;
int starWidth = boxWidth/numStarCol;
int starHeight = boxHeight/numStarRow;
/*public UsFlag() {
//ask user to enter number of stripes, star columns, and star rows
}*/
#Override
public void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
//Background
g.setColor(Color.RED);
g.fillRect(0, 0, w, h);
//Stripes
g.setColor(Color.WHITE);
for (int i = 0; i < numberStripes; i += 1) {
g.fillRect(0,stripeHeight, w, stripeHeight);
stripeHeight = stripeHeight + 45;
}
//Blue Rect
g.setColor(Color.BLUE);
g.fillRect(0, 0, boxWidth, boxHeight);
//stars
int y = 0;
int x = 0;
for (int j = 0; j < numStarRow; j++){
for (int i = 0; i < numStarCol; i++){
g.setColor(Color.WHITE);
g.fillOval(5, 5, starWidth, starHeight);
x += starWidth;
}
y += starHeight;
x = 0;
}
}
public static void main(String[] args) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(400, 400);
window.setContentPane(new UsFlag());
window.setVisible(true);
}
}
The first two parameters for the fillRect() method and the fillOval() method are considered coordinates (x & y) for the object you want to paint. This means that for x you need to place a integer pixel value as to where you want the Left edge of the object is to Start being painting from along the horizontal plain, and for y you need to place a integer pixel value as to where you want the Top edge of the object is to Start being painting from along the vertical plain. For fillRect() for example:
g.fillRect(20, 20, 100, 30);
The other two parameters are for the Width (w) and Height (h) in pixels of the object to paint. Use the the variable i from your for loop (y = i + 30; for example) to draw objects below one another. Read this for more information.
I'm trying to make a 2D game. I have an array of rectangles to represent attacks. I am trying to make them rotate so they are all rotated 45 degrees. When I try rendering more spells after the first, they glitch to random places around the screen. Here is my code:
Rectangle[] waterBolt = new Rectangle[10];
float[] wba = new float[10];
int wbc = 0;
Graphics2D[] gwb = new Graphics2D[10];
public void renderSpell(Graphics2D g) {
for(int i=0; i<10; i++) {
if (waterBolt[i] != null) {
gwb[i] = (Graphics2D) g;
gwb[i].rotate(Math.toRadian(45), waterBolt[i].x, waterBolt[i].y);
gwb[i].fill(waterBolt[i]);
}
}
}
public void castSpell(int spellID) {
waterBolt[wbc] = new Rectangle(playerX, playerY, 16, 16);
wba[wbc] = (float) Math.toRadians(Math.atan2(mouseX - playerX, mouseY - playerY));
wbc++;
if (wbc >= 10) {
wbc = 0;
}
}
And here is what is happening to my screen when I cast them all standing still:
They all rotate 45 more degrees every time I click to cast, but I don't know how to fix it.
Keep in mind that when you call gwb[i] = (Graphics2D) g;, you are not making a copy of g. Instead, each of your rectangles is being rotated by the cumulative sum of all of your previous rotations. Try something like this instead:
public void renderSpell(Graphics2D g) {
AffineTransform transform = g.getTransform();
for(int i=0; i<waterBolt.length; i++) {
if (waterBolt[i] != null) {
g.rotate(Math.toRadian(45), waterBolt[i].x, waterBolt[i].y);
g.fill(waterBolt[i]);
g.setTransform(transform); // back to original orientation
}
}
}
For quite a long time, 1-2 months, I have been trying to find an answer to this particular problem:
I can't get my image hardware accelerated!
I've been searching on the net, created my own methods, hit my head with the keyboard (still feel the pain) but no success.
Although I hate libraries other than Java SDK, I tried LWJGL and JOGL but for some stupid reason they dont work on my computer.
I tried using System.setProperty("Dsun.java2d.opengl", "True"), I used VolatileImage but I can't draw individual pixels to it.(I tried using drawLine(x,y,x,y) but it's slow)
Now I am so desperate. I will do anything to fix this! So please, if you know the solution (I know some of you do) tell me so I can get rid of this.
My code:
public static void render(int x, int y, int w, int h, ) {
int a[] = new int[3]; // The array that contains RGB values for every pixel
BufferedImage bImg = Launcher.contObj.getGraphicsConfiguration().createCompatibleImage(800, 600, Transparency.TRANSLUCENT); // Creates an image compatible to my JPanel (Runs at 20-24 FPS on 800x600 resolution)
int[] wr = ((DataBufferInt) bImg.getRaster().getDataBuffer()).getData(); // Contains the image data, used for drawing pixels
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] = i * j % 256;
wr[i + j * bImg.getWidth()] = new Color(a[0], a[1], a[2]).getRGB(); // Sets the pixels from a[]
}
}
bImg.flush();
g.drawImage(bImg, x, y, w, h, null); // Draws the image on the JPanel
g.dispose();
System.out.println(bImg.getCapabilities(Launcher.contObj.getGraphicsConfiguration()).isAccelerated()); // Prints out whether I was successful and made the image accelerated or failed and made everything worse
}
I hope you understand the code. Please modify it in any way to help me find the solution to my problems.
Note: Please don't post anything about external libraries unless you are absolutely sure that I can't get this working without them.
Also, could it be that my graphics card doesn't support acceleration? (because I saw posts where hardware accel works for other people but not for me) Btw, it's a GeForce 430 GT.
THANKS IN ADVANCE!
Source copied from : Java Hardware Acceleration not working with Intel Integrated Graphics
Try this:
package graphicstest;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
public class GraphicsTest extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GraphicsTest();
}
});
}
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
BufferCapabilities bufferCapabilities;
BufferStrategy bufferStrategy;
int y = 0;
int delta = 1;
public GraphicsTest() {
setTitle("Hardware Acceleration Test");
setSize(500, 300);
setLocationRelativeTo(null);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
createBufferStrategy(2);
bufferStrategy = getBufferStrategy();
bufferCapabilities = gc.getBufferCapabilities();
new AnimationThread().start();
}
class AnimationThread extends Thread {
#Override
public void run() {
while(true) {
Graphics2D g2 = null;
try {
g2 = (Graphics2D) bufferStrategy.getDrawGraphics();
draw(g2);
} finally {
if(g2 != null) g2.dispose();
}
bufferStrategy.show();
try {
// CHANGE HERE, DONT SLEEP
//Thread.sleep(16);
} catch(Exception err) {
err.printStackTrace();
}
}
}
}
public void draw(Graphics2D g2) {
if(!bufferCapabilities.isPageFlipping() || bufferCapabilities.isFullScreenRequired()) {
g2.setColor(Color.black);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(Color.red);
g2.drawString("Hardware Acceleration is not supported...", 100, 100);
g2.setColor(Color.white);
g2.drawString("Page Flipping: " + (bufferCapabilities.isPageFlipping() ? "Available" : "Not Supported"), 100, 130);
g2.drawString("Full Screen Required: " + (bufferCapabilities.isFullScreenRequired() ? "Required" : "Not Required"), 100, 160);
g2.drawString("Multiple Buffer Capable: " + (bufferCapabilities.isMultiBufferAvailable() ? "Yes" : "No"), 100, 190);
} else {
g2.setColor(Color.black);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(Color.white);
g2.drawString("Hardware Acceleration is Working...", 100, 100);
g2.drawString("Page Flipping: " + (bufferCapabilities.isPageFlipping() ? "Available" : "Not Supported"), 100, 130);
g2.drawString("Full Screen Required: " + (bufferCapabilities.isFullScreenRequired() ? "Required" : "Not Required"), 100, 160);
g2.drawString("Multiple Buffer Capable: " + (bufferCapabilities.isMultiBufferAvailable() ? "Yes" : "No"), 100, 190);
}
y += delta;
if((y + 50) > getHeight() || y < 0) {
delta *= -1;
}
g2.setColor(Color.blue);
g2.fillRect(getWidth()-50, y, 50, 50);
}
}
Output I got hardware accelaration not available. java.exe was taking 12% CPU. 700 FPS
Then I added System variable:
Variable name: J2D_D3D_NO_HWCHECK
Variable value: true
then restarted IDE, and ran program:
I got amazing result. I got hardware acceleration available. java.exe was taking 5% CPU. 1700 FPS. Animation was great!
Above things are to check whether hardware acceleration works in your system.
Now to your question:
AFAIK: You can't get real hardware acceleration with BufferedImage. You should work with VolatileImage to get hardware acceleration. But with VolatileImage, you can't get pixel data buffer to modify pixels. And rendering pixel by pixel using hardware doesn't make sense.
What I suggest:
1) Design your logic, which can render pixels using Graphics and Graphics2D of volatile image. But don't go to make hack like drawing lines of 1 pixel.
2) Use buffer strategies, double / triple buffering.
3) If you want to stick with BufferedImage for setting each pixel, use BufferedImage as data model, while rendering draw buffered image on volatile image. This will help a lot if you are scaling image.
4) Cache the images frequently being rendered.
5) Write code better, like:
int wi = bImg.getWidth();
int he = bImg.getHeight();
for (int i = 0; i < wi; i++) {
for (int j = 0; j < he; j++) {
wr[i + j * wi] = ((i % 256) << 16) | ((i * j % 256) << 8) | (j % 256);
}
}
6) For time consuming math operation like sqrt(), sin(), cos(), cache results of these operations and create lookup tables.