HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Slow rendering method

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
renderingslowmethod

Problem

The code works fine, but the speed stays at a consistent eight frames per second.
Today I fixed some pieces and got four more frames per second.
I figured out that the typecasting (int) and Math.floor() consume around 50 fps.

Is there anything I can do to improve the performance of this code?

public void render(){
    for(int y = 0; y = Game.WIDTH / 2 - 16 && x = Game.HEIGHT / 2 - 16 && y = Game.WIDTH / 2 - 16 && x = Game.HEIGHT / 2 - 16 && y  574 && y  290 && x  540 && x < 700){
                        Game.pixels[screenPix] = 0xffffffff;
                    }
                }
                continue;
            }
        }
    }
}


Some more context

TreeMap guiSprites = new TreeMap();


Game is the Main Class the produce a JFrame and some other stuff until it starts to call render() that actually calls the above code.

private void render() {
    bs = getBufferStrategy();
    if(bs == null){
        createBufferStrategy(2);
        return;
    }
    screen.render();
    g = bs.getDrawGraphics();
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, getWidth(), getHeight());
    g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
    g.dispose();
    bs.show();
}


And Core is a Class that handles information given by the server,
but for this part now it's just a few booleans for later in the game.

Solution

This is only a quick review, since I don't know much in the area of rendering graphics

Repeated Work

screenPix = x + y * width;

chunkY = (int) Math.floor((y + offsetY) / 512);

tileY = (int) Math.floor(((y + offsetY) - (chunkY * 512)) / 32);


There are many lines that are inside of a loop that do not need to be. Every time you move a pixel in the x direction, the inner loop, these results do not change, so you can save them in a variable outside of the x loop. This alone will save you a bunch of repeated calculations.

Modular Code

//render order: player object event
if(x >= Game.WIDTH / 2 - 16 && x = Game.HEIGHT / 2 - 16 && y <= Game.HEIGHT / 2 + 16){//wrong
    //TODO render player
    //TODO render equip
}
if(SpriteManager.objectSpritesGet(currTile.getObjectID()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.objectSpritesGet(currTile.getObjectID()).pixels[tilePix];
if(SpriteManager.objectSpritesGet(currTile.getObjectID2()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.objectSpritesGet(currTile.getObjectID2()).pixels[tilePix];
if(SpriteManager.objectSpritesGet(currTile.getObjectID3()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.objectSpritesGet(currTile.getObjectID3()).pixels[tilePix];
if(Core.builderMode){
    if(Core.builderModePathMode && SpriteManager.eventSpritesGet(currTile.getEventWalkPath()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.eventSpritesGet(currTile.getEventWalkPath()).pixels[tilePix];
    if(Core.builderModeEventMode && SpriteManager.eventSpritesGet(currTile.getEventID()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.eventSpritesGet(currTile.getEventID()).pixels[tilePix];
}else{
    if(SpriteManager.eventSpritesGet(currTile.getEventAlias()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.eventSpritesGet(currTile.getEventAlias()).pixels[tilePix];
}
continue;


The fact you need a comment to explain that the difference between this and later code is the order, shows that this is perfect to abstract to a method.

renderPlayer(x, y);
renderObject(tilePix, etc..);
renderEvent(Core.builderMode, tilePix, etc..);


This will make it much easier to read, and you don't have to change code in multiple places, such as if a value changes.

chunkX = (int) Math.floor((x + offsetX) / 512);


if x is an int, and offsetX is an int, we have

int = (int) Math.floor((int + int) / int);
=> int = (int) Math.floor(int / int);
=> int = (int) Math.floor(int);


Basically, you don't need to round down anything if everything inside is going to be an integer. This also means you don't have to cast the double you got from Math.floor back to an int, saving even more time.

chunkX = (x + offsetX) / 512;


512, 32, 2, 16


So many pretty powers of 2, I'm guessing it is deliberate. It is a good idea, it speeds up multiplication and division because x the micro-optimisations you implement. Low level changes like these make code harder to read, harder to change later, and more prone to bugs, if edge cases aren't accounted for. Do them last if you need the small boost to go from 58 fps to 60

Profile the code, and with each change test it again, the only way to really improve performance is to know where the bottleneck is. Sometimes it is in the last place you expect.

Code Snippets

screenPix = x + y * width;

chunkY = (int) Math.floor((y + offsetY) / 512);

tileY = (int) Math.floor(((y + offsetY) - (chunkY * 512)) / 32);
//render order: player object event
if(x >= Game.WIDTH / 2 - 16 && x <= Game.WIDTH / 2 + 16 && y >= Game.HEIGHT / 2 - 16 && y <= Game.HEIGHT / 2 + 16){//wrong
    //TODO render player
    //TODO render equip
}
if(SpriteManager.objectSpritesGet(currTile.getObjectID()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.objectSpritesGet(currTile.getObjectID()).pixels[tilePix];
if(SpriteManager.objectSpritesGet(currTile.getObjectID2()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.objectSpritesGet(currTile.getObjectID2()).pixels[tilePix];
if(SpriteManager.objectSpritesGet(currTile.getObjectID3()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.objectSpritesGet(currTile.getObjectID3()).pixels[tilePix];
if(Core.builderMode){
    if(Core.builderModePathMode && SpriteManager.eventSpritesGet(currTile.getEventWalkPath()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.eventSpritesGet(currTile.getEventWalkPath()).pixels[tilePix];
    if(Core.builderModeEventMode && SpriteManager.eventSpritesGet(currTile.getEventID()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.eventSpritesGet(currTile.getEventID()).pixels[tilePix];
}else{
    if(SpriteManager.eventSpritesGet(currTile.getEventAlias()).pixels[tilePix] != 0xffff00ff) Game.pixels[screenPix] = SpriteManager.eventSpritesGet(currTile.getEventAlias()).pixels[tilePix];
}
continue;
renderPlayer(x, y);
renderObject(tilePix, etc..);
renderEvent(Core.builderMode, tilePix, etc..);
chunkX = (int) Math.floor((x + offsetX) / 512);
int = (int) Math.floor((int + int) / int);
=> int = (int) Math.floor(int / int);
=> int = (int) Math.floor(int);

Context

StackExchange Code Review Q#104164, answer score: 4

Revisions (0)

No revisions yet.