LWJGL Screwed textures - java

I'm currently working on a game with java & lwjgl and in my main menu I try to draw a background image. For some reason, whatever texture loading and drawing technique i use, the image gets screwed up completely.
This is what happens:
And this is what it's supposed to look like:
This is my code for loading the texture:
private int loadTexture(String imgName) {
try {
BufferedImage img = ImageIO.read(JarStreamLoader.load(imgName));
ByteBuffer buffer = BufferUtils.createByteBuffer(img.getWidth() * img.getHeight() * 3);
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
Color color = new Color(img.getRGB(x, y));
buffer.put((byte) color.getRed());
buffer.put((byte) color.getGreen());
buffer.put((byte) color.getBlue());
}
}
buffer.flip();
int textureId = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.getWidth(), img.getHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return textureId;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
And that's my rendering code:
public static void drawRect(int x, int y, int width, int height, Color color) {
glColor4f(color.getRed() / 255, color.getGreen() / 255, color.getBlue() / 255, 1.0F);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2d(x, y);
glTexCoord2f(0.0f, 1.0F);
glVertex2d(x, y + height);
glTexCoord2f(1.0F, 1.0F);
glVertex2d(x + width, y + height);
glTexCoord2f(1.0F, 0.0f);
glVertex2d(x + width, y);
glEnd();
}
Any Ideas?

You're adding the pixels in the wrong order. You need to do it in this order:
for (int y = 0; y < img.getHeight(); y++)
for (int x = 0; x < img.getWidth(); x++)
Note that OpenGL's origin is at the bottom left corner, so you might have to flip the image on the y-axis as well:
Color color = new Color(img.getRGB(x, img.getHeight() - y - 1));

Related

How can I draw colorful Emoji in Java Graphics2D?

I am trying to render text in LWJGL(Minecraft), but i got some problem.
I am trying to draw colorful emoji in Java Graphics2D, but it can't work normally.
You can see, the Graphics2D draw a black and white character.
My final goal is render Emoji in LWJGL(Minecraft).
If you want more infomation, you can tell me.
Imgur Drawing Bed
China Drawing Bed
Key Source Code:
public BufferedImage createCharImage(int cp){
Objects.requireNonNull(this.font);
Objects.requireNonNull(this.fontMetrics);
int charWidth = this.fontMetrics.charWidth(cp);
int charHeight = this.fontMetrics.getHeight();
BufferedImage image = new BufferedImage(charWidth, charHeight, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g = image.createGraphics();
if(this.antiAlias){
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
g.setFont(this.font);
g.drawString(String.valueOf(Character.toChars(cp)), 0, this.fontMetrics.getAscent());
g.dispose();
return image;
}
Full Source Code:
private final Font font;
private FontMetrics fontMetrics;
private boolean antiAlias;
private boolean lineWrap;
public FontRenderer(Font font){
Objects.requireNonNull(font);
this.font = font;
this.antiAlias = true;
this.lineWrap = true;
initFontRenderer();
}
public FontRenderer(File fontFile, int size){
Objects.requireNonNull(fontFile);
this.font = FontUtils.readFontFromTTF(fontFile, size);
this.antiAlias = true;
this.lineWrap = true;
initFontRenderer();
}
public Font getFont(){
return this.font;
}
public void setAntiAlias(boolean antiAlias){
this.antiAlias = antiAlias;
}
public void setLineWrap(boolean lineWrap){
this.lineWrap = lineWrap;
}
private void initFontRenderer(){
this.initFontMetrics();
// Reject HardCode!
}
private void initFontMetrics(){
Objects.requireNonNull(this.font);
// TYPE_INT_ARGB
// TYPE_4BYTE_ABGR
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g = image.createGraphics();
// Anti Alias
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setFont(this.font);
this.fontMetrics = g.getFontMetrics();
g.dispose();
}
public BufferedImage createCharImage(int cp){
Objects.requireNonNull(this.font);
Objects.requireNonNull(this.fontMetrics);
int charWidth = this.fontMetrics.charWidth(cp);
int charHeight = this.fontMetrics.getHeight();
BufferedImage image = new BufferedImage(charWidth, charHeight, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g = image.createGraphics();
if(this.antiAlias){
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
g.setFont(this.font);
g.setPaint(Color.WHITE);
g.drawString(String.valueOf(Character.toChars(cp)), 0, this.fontMetrics.getAscent());
g.dispose();
return image;
}
private HashMap<Integer, CharTexture> textureMap;
public void drawString(String s, double x, double y){
if(textureMap == null){
textureMap = new HashMap<Integer, CharTexture>();
}
double lineWidth = 0;
double lineHeight = this.fontMetrics.getHeight();
double linesHeight = 0;
int cplength = s.codePointCount(0, s.length());
for(int i = 0; i < cplength; i++){
int cpi = s.offsetByCodePoints(0, i);
int cp = s.codePointAt(cpi);
String cps = String.valueOf(Character.toChars(cp));
if(cps == "\n"){/*1*/
lineWidth = 0;
linesHeight += lineHeight;
}else{/*1*/
CharTexture texture;
if(textureMap.containsKey(cp)){
texture = textureMap.get(cp);
}else{
BufferedImage image = this.createCharImage(cp);
int width = image.getWidth();
int height = image.getHeight();
int textureId = RenderUtils.uploadTextureImage(image);
texture = new CharTexture(width, height, textureId);
textureMap.put(cp, texture);
}
// render
RenderUtils.drawImage(
texture.textureId,
(x + lineWidth),
(y + linesHeight),
(x + lineWidth + texture.width),
(y + linesHeight + texture.height)
);
lineWidth += texture.width;
}/*1*/
}
}
RenderUtils.java
public static ByteBuffer readImageToBuffer(BufferedImage bufferedImage){
int[] rgb = bufferedImage.getRGB(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), null, 0, bufferedImage.getWidth());
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4 * rgb.length);
for(int i : rgb){
byteBuffer.putInt(i << 8 | i >> 24 & 255);
}
byteBuffer.flip();
return byteBuffer;
}
public static int uploadTextureImage(BufferedImage bufferedImage){
int textureId = GL11.glGenTextures();
// https://www.jianshu.com/p/1b327789220d
// 纹理
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
// 设置纹理包装和过滤的方式
// GL_CLAMP_TP_EDGE 和 GL_CLAMP_TO_BORDER 和 GL_MIRRORED_REPEAT会报错 1280: Invalid enum
// May be because the enum is not available in this lwjgl
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexImage2D(
GL11.GL_TEXTURE_2D,
0,
GL11.GL_RGBA,
bufferedImage.getWidth(),
bufferedImage.getHeight(),
0,
GL11.GL_RGBA,
GL11.GL_UNSIGNED_BYTE,
readImageToBuffer(bufferedImage)
);
return textureId;
}
public static void drawImage(int textureId, double x, double y, double x2, double y2) {
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2d(1,0);
GL11.glVertex2d(x2, y);
GL11.glTexCoord2d(0, 0);
GL11.glVertex2d(x, y);
GL11.glTexCoord2d(0, 1);
GL11.glVertex2d(x, y2);
GL11.glTexCoord2d(1,1);
GL11.glVertex2d(x2, y2);
GL11.glEnd();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glDisable(GL11.GL_BLEND);
GL11.glDisable(GL11.GL_TEXTURE_2D);
}

Drawing graphics in Java

I am trying to draw a circle in side a square and having multiple square circles in java. I am almost done but my output isn't coming out as I wanted to. The picture is what I am trying to do but it's not working out.
Here is my code:
a.awt.*;
public class SquaredCircles {
public static final int WIDTH=400;
public static final int HEIGHT=400;
public static void main (String[] args) {
DrawingPanel panel = new DrawingPanel(WIDTH,HEIGHT);
Graphics g = panel.getGraphics ();
panel.setBackground(new Color(0, 255, 255 ) );
int x = 0;
int y = 0;
int size = 100;
int rows = 5;
int numSquares = 1;
drawManySquares ( g, numSquares, x, y, size, rows );
x = 10;
y = 120;
size = 24;
rows = 4;
numSquares = 4;
drawManySquares( g, numSquares, x, y, size, rows );
x = 150;
y = 20;
size = 40;
rows = 6;
numSquares = 5;
drawManySquares( g, numSquares, x, y, size, rows );
x = 130;
y = 275;
size = 36;
rows = 3;
numSquares = 3;
drawManySquares( g, numSquares, x, y, size, rows );
}
public static void drawManySquares( Graphics g, int numSquares, int x, int y, int size, int rows ) {
for ( int i = 0; i < numSquares; i++ ) {
for ( int j = 0; j < numSquares; j++ ) {
drawOneSquare( g, x + i size, y + j size, size, rows );
}
}
}
public static void drawOneSquare( Graphics g, int x, int y, int size, int rows ) {
g.setColor ( Color.GREEN);
g.fillRect(x , y, size, size);
g.setColor ( Color.YELLOW);
g.fillOval ( x, y, size, size);
g.setColor ( Color.BLACK);
g.drawLine(size / 2, x, size / 2, size);
g.setColor ( Color.BLACK);
g.drawLine(x, size / 2, size, size / 2);
for (int i = 0; i <= rows; i = i + 1) {
g.setColor ( Color.BLACK);
g.drawOval(x + (i* (size/rows)), y+ (i*(size/rows)), size - (i*(size/rows +10 )) , size - (i*(size/rows +10)));
}
}
}
Start by having a look at Painting in AWT and Swing and Performing Custom Painting to see how painting should be done in Swing
Break down your problem into manageable chunks. The first thing you need to be able to do is paint a circle of a given size at a specific location, something like
public void paintCircleAt(Graphics2D g2d, int radius, int centerX, int centerY, Color stroke, Color fill) {
Ellipse2D.Double circle = new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2);
g2d.setColor(fill);
g2d.fill(circle);
g2d.setColor(stroke);
g2d.draw(circle);
}
So, this allows you to paint a circle of a given radius around the center points of x/y filled and outlined with the specified color, pretty simple.
Now, you need someway to paint a series of circles around the same center point, something like...
public void paintCirclesIn(Graphics2D g2d, int count, int radius, int centerX, int centerY, Color stroke, Color fill) {
System.out.println(radius + "; " + centerX + "; " + centerY);
int delta = radius / count;
int innerRadius = radius;
for (int index = 0; index < count; index++, innerRadius -= delta) {
paintCircleAt(g2d, innerRadius, centerX, centerY, stroke, fill);
}
}
Okay, this basically calculates the difference (delta) between each circle and the paints that many circles with that much difference in their radius from the previous one. Because of the way the painting is done, we start with the outer circle and paint in.
And finally, we need someway to paint a square and circles, something like...
public void paintCirclesInSquare(Graphics2D g2d, int count, int x, int y, int width, int height, Color squareStroke, Color squareFill, Color circleStroke, Color circleFill) {
int centerX = x + (width / 2);
int centerY = y + (height / 2);
int radius = Math.min(centerX, centerY);
Rectangle2D box = new Rectangle2D.Double(x, y, width, height);
g2d.setColor(squareFill);
g2d.fill(box);
g2d.setColor(squareStroke);
g2d.draw(box);
paintCirclesIn(g2d, count, radius, centerX, centerY, circleStroke, circleFill);
g2d.drawLine(centerX, y, centerX, y + height);
g2d.drawLine(x, centerY, x + width, centerY);
}
This, again, simply reuses the existing code we already have and adds to it, painting the square, the circles in the square and finally the lines.
Now, from here, you could write a method which took the number of columns/rows you wanted, the x/y position to start from, the size of each of square, the number of circles you need and the colors and reuse this functionality, but I'll leave that up to you ;)
Runnable example for you to play with...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class CirclesAndSquares {
public static void main(String[] args) {
new CirclesAndSquares();
}
public CirclesAndSquares() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
int x = getWidth() / 2;
int y = getHeight() / 2;
// paintCircleAt(g2d, Math.min(x, y), y, y, Color.BLACK, Color.YELLOW);
// paintCirclesIn(g2d, 5, Math.min(x, y), x, y, Color.BLACK, Color.YELLOW);
paintCirclesInSquare(g2d, 5, 0, 0, getWidth() - 1, getHeight() - 1, Color.BLACK, Color.GREEN, Color.BLACK, Color.YELLOW);
g2d.dispose();
}
public void paintCirclesInSquare(Graphics2D g2d, int count, int x, int y, int width, int height, Color squareStroke, Color squareFill, Color circleStroke, Color circleFill) {
int centerX = x + (width / 2);
int centerY = y + (height / 2);
int radius = Math.min(centerX, centerY);
Rectangle2D box = new Rectangle2D.Double(x, y, width, height);
g2d.setColor(squareFill);
g2d.fill(box);
g2d.setColor(squareStroke);
g2d.draw(box);
paintCirclesIn(g2d, count, radius, centerX, centerY, circleStroke, circleFill);
g2d.drawLine(centerX, y, centerX, y + height);
g2d.drawLine(x, centerY, x + width, centerY);
}
public void paintCirclesIn(Graphics2D g2d, int count, int radius, int centerX, int centerY, Color stroke, Color fill) {
System.out.println(radius + "; " + centerX + "; " + centerY);
int delta = radius / count;
int innerRadius = radius;
for (int index = 0; index < count; index++, innerRadius -= delta) {
paintCircleAt(g2d, innerRadius, centerX, centerY, stroke, fill);
}
}
public void paintCircleAt(Graphics2D g2d, int radius, int centerX, int centerY, Color stroke, Color fill) {
Ellipse2D.Double circle = new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2);
g2d.setColor(fill);
g2d.fill(circle);
g2d.setColor(stroke);
g2d.draw(circle);
}
}
}

Using Bitmap to draw an image in Android

I need to put a random image inside a screen with given resolution (640x480, 1280x720, etc). I finished it in Java. In Android do not support the BufferedImage and Graphics2D, I wonder if there is a way to replace this code from Java to Android. Here is my code from Java:
public BufferedImage resizeImage(BufferedImage originalImage, int type){
BufferedImage resizedImage = new BufferedImage(screenWidth, screenHeight, type);
Graphics2D g = resizedImage.createGraphics();
int imgWidth = originalImage.getWidth();
int imgHeight = originalImage.getHeight();
int newImgWidth = 0;
int newImgHeight = 0;
int X = 0;
int Y = 0;
if (imgWidth > screenWidth){
// scale width to fit
newImgWidth = screenWidth;
//scale height to maintain aspect ratio
newImgHeight = (newImgWidth * imgHeight) / imgWidth;
}
if (newImgHeight > screenHeight) {
//scale height to fit instead
newImgHeight = screenHeight;
//scale width to maintain aspect ratio
newImgWidth = (newImgHeight * imgWidth) / imgHeight;
}
if (imgWidth < screenWidth && imgHeight < screenHeight) {
X = screenWidth/2 - imgWidth/2;
Y = screenHeight/2 - imgHeight/2;
g.drawImage(originalImage, X, Y, imgWidth, imgHeight, null);
g.dispose();
return resizedImage;
}
X = screenWidth/2 - newImgWidth/2;
Y = screenHeight/2 - newImgHeight/2;
g.drawImage(originalImage, X, Y, newImgWidth, newImgHeight, null);
g.dispose();
return resizedImage;
}
Thank you in advance!

Healthy way of drawing grid lines in LibGdx

So, I wanted to draw a grid in my game and as I was writing it out, it seemed incredibly unusual (at least to me) in terms of efficiency. I've got two for loops inside a render method which is used to render the game, so it is called very often and fast.
Is this ShapeRenderer portion a red flag?
public void render(float deltaTime) {
Gdx.gl.glClearColor(Color.GRAY.r, Color.GRAY.g, Color.GRAY.b, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
this.world.getPlayer().render(deltaTime, batch);
batch.end();
// Gridlines
shape.begin(ShapeType.Line);
shape.setColor(Color.BLACK);
for (int i = 0; i < Gdx.graphics.getHeight() / 32; i++) {
shape.line(0, i * 32, Gdx.graphics.getWidth(), i * 32);
}
for (int i = 0; i < Gdx.graphics.getWidth() / 32; i++) {
shape.line(i * 32, 0, i * 32, Gdx.graphics.getHeight());
}
shape.end();
}
You could use fast, simple and powerful ImmediateModeRenderer20.
Please have a look on the following code with PerspectiveCamera:
// init primitive renderer
ImmediateModeRenderer20 lineRenderer = new ImmediateModeRenderer20(false, true, 0);
// create atomic method for line
public static void line(float x1, float y1, float z1,
float x2, float y2, float z2,
float r, float g, float b, float a) {
lineRenderer.color(r, g, b, a);
lineRenderer.vertex(x1, y1, z1);
lineRenderer.color(r, g, b, a);
lineRenderer.vertex(x2, y2, z2);
}
// method for whole grid
public static void grid(int width, int height) {
for (int x = 0; x <= width; x++) {
// draw vertical
line(x, 0, 0,
x, 0, -height,
0, 1, 0, 0);
}
for (int y = 0; y <= height; y++) {
// draw horizontal
line(0, 0, -y,
width, 0, -y,
0, 1, 0, 0);
}
}
// init 3d camera
PerspectiveCamera perspectiveCamera = new PerspectiveCamera(55, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// your render loop {
perspectiveCamera.update();
lineRenderer.begin(perspectiveCamera.combined, GL30.GL_LINES);
//... lineRenderer works a lot
grid(10, 10);
//... lineRenderer works a lot
lineRenderer.end();
//}
Hope it helps!

Canvas - good rendering practices?

I've been using the Canvas a lot lately for little Java games and i've noticed a lot of strange things can happen. For example, earlier today I created a little game in which the objective is to shoot enemy ships and get points. The game draws tiny 32x32 images on the screen (sometimes slightly bigger) and for a reason I am oblivious to, the game renders oddly.
For example, my ship has a health bar above it's head:
As you can see by the image, the textures are really small. Despite this, the game lags and sometimes things render incorrectly like this for example:
If you look closely at the top of the health bar, you can see that it's been shifted upwards slightly, it puzzles me how his happens as all of my rendering is buffered.
My rendering code:
public void render(){
BufferStrategy bs = getBufferStrategy();
if(bs == null){
createBufferStrategy(3);
return;
}
Graphics2D g = (Graphics2D)bs.getDrawGraphics();
toDrawG.setColor(new Color(0x222222));
toDrawG.fillRect(0, 0, WIDTH, HEIGHT);
draw((Graphics2D)toDrawG);
g.drawImage(toDraw, 0, 0, null);
g.dispose();
bs.show();
}
public void draw(Graphics2D g){
if(Settings.planets){
renderer.renderPlanets();
}
if(level != null){
for(int i = 0 ; i < level.entityList.size(); i++){
if(level.entityList.get(i) != null){
level.entityList.get(i).render(renderer);
}
}
}
renderer.overlayString("Space Game", 20, 20, 24, 0xFFFFFF);
renderer.overlayString(VERSION, 20, 50, 24, 0xFFFFFF);
renderer.overlayString("FPS: " + renderer.fps, 20, 70, 24, 0xFFFFFF);
renderer.overlayString("Ships spawned: " + level.shipsSpawned, 20, 90, 24, 0xFFFFFF);
renderer.overlayString("Time Survived: " + level.time / 100 + "s", 20, 110, 24, 0xFFFFFF);
renderer.overlayString("Physics FPS: " + fps, 20, 130, 24, 0xFFFFFF);
if(currentGui != null){
currentGui.render(renderer);
}else{
map.drawMinimap(SpaceGame.WIDTH-Minimap.WIDTH-20, SpaceGame.HEIGHT- Minimap.HEIGHT-30);
}
}
And my "Render.class" if you need to study it:
package com.maestrum;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.util.Random;
public class Render implements Runnable{
public Graphics2D g2d;
public double xScroll,yScroll;
public int frames;
public int fps;
public long lastTime;
public int[] pSequence = new int[40];
public SpaceGame game;
public Entity trackedEntity;
public Random rand;
public Render(SpaceGame game, Graphics2D g){
this.game = game;
this.g2d = g;
this.rand = new Random();
for(int i = 0 ; i < 40; i++){
pSequence[i] = rand.nextInt(15) + 1;
}
}
#Override
public void run() {
renderLoop();
}
public void renderLoop(){
while(true){
game.render();
if(System.currentTimeMillis() - lastTime >= 1000){
fps = frames;
frames = 0;
lastTime = System.currentTimeMillis();
}
frames++;
}
}
public void renderPlanets(){
overlayImage(ImageHandler.background, 0, 0, 1.5);
for(int i = 0 ; i < 20; i++){
overlayImage(ImageHandler.planets[pSequence[i]/4][pSequence[i]%4], i * 400 - xScroll/pSequence[i], i * pSequence[i]*40 - yScroll/pSequence[i]*2, pSequence[i]);
}
}
private class PlanetRenderer {
}
public void overlayString(String s, double x, double y, int fontSize, int colour){
drawString(s, x+xScroll, y+yScroll, fontSize, colour);
}
public void overlayRectangle(double x, double y, int xs, int ys, int colour){
drawRectangle(x+xScroll, y+yScroll, xs, ys, colour);
}
public void overlayBlurred(BufferedImage img, double x, double y, double scale){
drawImageBlurred(img, x+xScroll, y+yScroll, scale);
}
public void overlayImage(BufferedImage img, double x, double y, double scale){
drawImage(img, x+xScroll, y+yScroll, scale);
}
public BufferedImage execute(BufferedImage img) {
// TODO Auto-generated method stub
float weight = 1.0f/2.0f;
float [] elements = {weight, weight, weight, weight, weight, weight, weight, weight, weight};
Kernel k = new Kernel (3,3,elements);
ConvolveOp op = new ConvolveOp(k);
BufferedImage dest = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
op.filter(img, dest);
return dest;
}
public void drawImageBlurred(BufferedImage img, double x, double y, double scale){
x -= xScroll;
y -= yScroll;
BufferedImage image = new BufferedImage((int)(img.getWidth()*scale), (int)(img.getHeight()*scale), BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.drawImage(img, 0, 0, (int)(img.getWidth()*scale), (int)(img.getHeight()*scale), null);
execute(image);
g2d.drawImage(image, (int)x, (int)y, null);
g.dispose();
}
public void drawString(String s, Vector2D pos, int fontSize, int colour){
drawString(s, pos.x, pos.y, fontSize, colour);
}
public void drawString(String s, double x, double y, int fontSize, int colour){
if(s == null){
return;
}
x -= xScroll;
y -= yScroll;
BufferedImage img = new BufferedImage(s.length()*fontSize+1, fontSize*2, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.getGraphics();
g.setColor(new Color(colour));
g.setFont(new Font("Consolas", Font.BOLD, fontSize));
g.drawString(s, 0, img.getHeight()/2);
g2d.drawImage(img, (int)x, (int)y, null);
g.dispose();
}
public void drawImage(BufferedImage img, Vector2D pos, double scale){
drawImage(img, pos.x, pos.y, scale);
}
public void drawLine(Vector2D v1, Vector2D v2, int colour, int width){
drawLine(v1.x, v1.y, v2.x, v2.y, colour, width);
}
public void drawLine(double x1, double y1, double x2, double y2, int colour, int lWidth){
x1 -= xScroll;
y1 -= yScroll;
x2 -= xScroll;
y2 -= yScroll;
g2d.setColor(new Color(colour));
g2d.setStroke(new BasicStroke(lWidth));
g2d.drawLine((int)x1, (int)y1, (int)x2, (int)y2);
}
public void drawImage(BufferedImage img, double x, double y, double scale){
x -= xScroll;
y -= yScroll;
BufferedImage image = new BufferedImage((int)(img.getWidth()*scale), (int)(img.getHeight()*scale), BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.drawImage(img, 0, 0, (int)(img.getWidth()*scale), (int)(img.getHeight()*scale), null);
g2d.drawImage(image, (int)x, (int)y, null);
g.dispose();
}
public void drawRectangle(Vector2D pos, int xs, int ys, int colour){
drawRectangle(pos.x, pos.y, xs, ys, colour);
}
public void drawRectangle(double x, double y, int xs, int ys, int colour){
if(xs <= 0){
return;
}
x -= xScroll;
y -= yScroll;
BufferedImage image = new BufferedImage(xs, ys, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) image.getGraphics();
g.setColor(new Color(colour));
g.fillRect(0, 0, xs, ys);
g2d.drawImage(image, (int)x, (int)y, null);
g.dispose();
}
public void drawImageRotated(BufferedImage img, Vector2D pos, double scale, double angle) {
drawImageRotated(img, pos.x, pos.y, scale, angle);
}
public void drawImageRotated(BufferedImage img, double x, double y, double scale, double angle) {
x -= xScroll;
y -= yScroll;
BufferedImage image = new BufferedImage((int)(img.getWidth() * 1.5D), (int)(img.getHeight() * 1.5D), 2);
Graphics2D g = (Graphics2D)image.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.rotate(Math.toRadians(angle), image.getWidth() / 2, image.getHeight() / 2);
g.drawImage(img, image.getWidth() / 2 - img.getWidth() / 2, image.getHeight() / 2 - image.getHeight() / 2, null);
g2d.drawImage(image, (int)(x-image.getWidth()*scale/2), (int)(y-image.getHeight()*scale/2), (int)(image.getWidth()*scale), (int)(image.getHeight()*scale), null);
g.dispose();
}
}
As you can see in the rendering class, the render process is done as many times a second as possible. This is to give the game the highest possible FPS. If you missed the point of what I'm asking; What good practices should I take into account when rendering stuff using Java? And, what could possibly be causing the space ships health bar to render like so?
NOTE: take a look at this video, I ran that program and got 80FPS with 50000 particles, however with my rendering code (which is obviously of a much lower quality) I can render only a mere 100 or so particles, before things start messing up.
http://www.youtube.com/watch?v=6M3Ze4Eu87Y
This is my tick() function, it gets called every game tick (10ms)
public void tick(){
if(System.currentTimeMillis() - lastTime >= 1000){
fps = frames;
frames = 0;
lastTime = System.currentTimeMillis();
}
frames++;
if(renderer.trackedEntity != null){
renderer.xScroll = renderer.trackedEntity.pos.x-SpaceGame.WIDTH/2;
renderer.yScroll = renderer.trackedEntity.pos.y-SpaceGame.HEIGHT/2;
}
if(level != null && !paused){
level.tick();
}
if(currentGui != null && currentGui.pausesGame()){
paused = true;
}else{
paused = false;
}
}
i think the answer by #mantrid should fix your problem.
as far as performance goes ... there are some obvious "sins" in your code:
Don't draw an image into an image to draw an image
public void drawImage(BufferedImage img, double x, double y, double scale){
x -= xScroll;
y -= yScroll;
BufferedImage image = new BufferedImage((int)(img.getWidth()*scale), (int)(img.getHeight()*scale), BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.drawImage(img, 0, 0, (int)(img.getWidth()*scale), (int)(img.getHeight()*scale), null);
g2d.drawImage(image, (int)x, (int)y, null);
g.dispose();
}
I don't see the point of this. Why not just do this:
public void drawImage(BufferedImage img, double x, double y, double scale){
g2d.drawImage(img, (int)(x-xScroll), (int)(y-yScroll), (int)(img.getWidth()*scale), (int)(img.getHeight()*scale), null);
}
AAAAAAAAAAAAA
The next one actually burnt my eyes
public void drawRectangle(double x, double y, int xs, int ys, int colour){
if(xs <= 0){
return;
}
x -= xScroll;
y -= yScroll;
BufferedImage image = new BufferedImage(xs, ys, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) image.getGraphics();
g.setColor(new Color(colour));
g.fillRect(0, 0, xs, ys);
g2d.drawImage(image, (int)x, (int)y, null);
g.dispose();
}
Why? This is so much simpler and quicker:
public void drawRectangle(double x, double y, int xs, int ys, int colour){
if(xs <= 0)
return;
g2d.setColor(new Color(colour));
g2d.fillRect((int)(x-xScroll), (int)(y-yScroll), xs, ys);
}
The same goes for the drawImageRotated and drawString.
Just draw to the g2d buffer directly, what are you afraid of?
drawImageBlurred
First of all... you're doing it again!
Second: You seem to be applying a convolve operation to an image on each frame, why not just do that operation once (e.g. at the start of the app, or even better yet, in an image editing program).
I don't mean this in a bad way at all, but you are clearly not very experienced with programming in general. I think you could take a look at processing (http://processing.org). I'm sort of biased here because i'm using it myself almost everyday. It is a great learning and prototyping environment written in java that should allow you to stop thinking about implementation details (like flipping buffers) and focus on what you really care for (make a game!).
Alright, hope what i said makes sense. Good luck with your coding! :)
The health bar might be shifted because when game lags, xScroll and yScroll are updated while components/overlays are still being rendered into backbuffer.
To fix that:
1) move game objects proportionally to amout of time elapsed from latest update to keep game speed always constant. add delta parameter to level.tick() and all game objects update method
2) put level.tick() and game.render() within the same loop sequence to ensure game objects are updated first:
currentTime = System.currentTimeMillis();
delta = currentTime - lastTime;
if(level != null && !paused){
level.tick(delta); // introduce delta here
game.render();
}
lastTime = currentTime;
In general, consider these additional steps:
1) set Component.setIgnoreRepaint(true) to speed up rendering
2) optimize images for current display at the start
GraphicsConfiguration gc = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDefaultConfiguration();
Image optimized = gc.createCompatibleImage(img.getWidth(),img.getHeight(),Transparency.BITMASK);
optimized.getGraphics().drawImage(unoptimized, 0, 0, null);

Categories