2012-03-10 15 views
0

私は、周期表のレンダリングを含む学校向けの小さなプロジェクトをまとめています。私はこれを行うためにLWJGLを使用することを選択しました。しかし問題は、私がテーブルをレンダリングすると、ゲームは30fps(60fpsで上限)から始まり、すぐに1桁のfpsに変動します。私はこの問題がメモリリークの可能性があると確信していますが、わかりません。誰も私のコードで目障りな問題を見ることができますか?私のLWJGLゲームのパフォーマンスを向上させる最も良い方法は?

EntityPeriodicTable:巨大な配列のEntityElementオブジェクト(以下を参照)を保持し、ロジック(tick()およびupdateInput())をアクティブにすることを担当します。 パッケージcom.flafla2.periodicTable;

import org.lwjgl.opengl.GL11; 

public class EntityPeriodicTable extends ClickableEntity { //ClickableEntity is an abstract class in charge of the tick(), updateInput(), and render() methods, as well as positioning 

    public EntityElement[] elements = {//This is unfinished, but you get the idea. 
     //new EntityElement(AtomiC#, State, Metal, "Symbol", "Name", new Vector2D(posx,posy), this) 
     new EntityElement(1, 2, 2, "H", "Hydrogen", new Vector2D(1,1), this), 
     new EntityElement(2, 2, 2, "He", "Helium", new Vector2D(18,1), this), 

     new EntityElement(3, 0, 0, "Li", "Lithium", new Vector2D(1,2), this), 
     new EntityElement(4, 0, 0, "Be", "Beryllium", new Vector2D(2,2), this), 
     new EntityElement(5, 0, 1, "B", "Boron", new Vector2D(13,2), this), 
     new EntityElement(6, 0, 2, "C", "Carbon", new Vector2D(14,2), this), 
     new EntityElement(7, 2, 2, "N", "Nitrogen", new Vector2D(15,2), this), 
     new EntityElement(8, 2, 2, "O", "Oxygen", new Vector2D(16,2), this), 
     new EntityElement(9, 2, 2, "F", "Fluorine", new Vector2D(17,2), this), 
     new EntityElement(10,2, 2, "Ne", "Neon", new Vector2D(18,2), this), 

     new EntityElement(11, 0, 0, "Na", "Sodium", new Vector2D(1,3), this), 
     new EntityElement(12, 0, 0, "Mg", "Magnesium", new Vector2D(2,3), this), 
     new EntityElement(13, 0, 0, "Al", "Aluminum", new Vector2D(13,3), this), 
     new EntityElement(14, 0, 1, "Si", "Silicon", new Vector2D(14,3), this), 
     new EntityElement(15, 0, 2, "P", "Phosphorous", new Vector2D(15,3), this), 
     new EntityElement(16, 0, 2, "S", "Sulfur", new Vector2D(16,3), this), 
     new EntityElement(17, 2, 2, "Cl", "Chlorine", new Vector2D(17,3), this), 
     new EntityElement(18, 2, 2, "Ar", "Argon", new Vector2D(18,3), this), 

     new EntityElement(19, 0, 0, "K", "Potassium", new Vector2D(1,4), this), 
     new EntityElement(20, 0, 0, "Ca", "Calcium", new Vector2D(2,4), this), 
     new EntityElement(21, 0, 0, "Sc", "Scandium", new Vector2D(3,4), this), 
     new EntityElement(22, 0, 0, "Ti", "Hydrogen", new Vector2D(4,4), this), 
     new EntityElement(23, 0, 0, "V", "Hydrogen", new Vector2D(5,4), this), 
     new EntityElement(24, 0, 0, "Cr", "Hydrogen", new Vector2D(6,4), this), 
     new EntityElement(25, 0, 0, "Mn", "Hydrogen", new Vector2D(7,4), this), 
     new EntityElement(26, 0, 0, "Fe", "Hydrogen", new Vector2D(8,4), this), 
     new EntityElement(27, 0, 0, "Co", "Hydrogen", new Vector2D(9,4), this), 
     new EntityElement(28, 0, 0, "Ni", "Hydrogen", new Vector2D(10,4), this), 
     new EntityElement(29, 0, 0, "Cu", "Hydrogen", new Vector2D(11,4), this), 
     new EntityElement(30, 0, 0, "Zn", "Hydrogen", new Vector2D(12,4), this), 
     new EntityElement(31, 0, 0, "Ga", "Hydrogen", new Vector2D(13,4), this), 
     new EntityElement(32, 0, 1, "Ge", "Hydrogen", new Vector2D(14,4), this), 
     new EntityElement(33, 0, 1, "As", "Hydrogen", new Vector2D(15,4), this), 
     new EntityElement(34, 0, 2, "Se", "Hydrogen", new Vector2D(16,4), this), 
     new EntityElement(35, 1, 2, "Br", "Hydrogen", new Vector2D(17,4), this), 
     new EntityElement(36, 2, 2, "Kr", "Hydrogen", new Vector2D(18,4), this), 
    }; 

    public final int ELEMENT_SIZE = 40; 
    public Vector2D mousePos = new Vector2D(0,0); //Simple 2D vector struct. 

    public double[] SOLID_RGB = {0,0,0}; 
    public double[] LIQUID_RGB = {0,0,1}; 
    public double[] GAS_RGB = {1,0,0}; 

    public double[] METAL_RGB; 
    public double[] NONMETAL_RGB; 
    public double[] METALLOID_RGB; 
    public double[] RECENT_RGB; 

    public EntityPeriodicTable(Vector2D pos) { 
     this.pos = pos; 
     METAL_RGB = new double[3]; 
     METAL_RGB[0] = 0.596078431; //152/255 
     METAL_RGB[1] = 0.984313725; //251/255 
     METAL_RGB[2] = 0.596078431; //152/255 

     NONMETAL_RGB = new double[3]; 
     NONMETAL_RGB[0] = 1; 
     NONMETAL_RGB[1] = 0.647058824; //165/255 
     NONMETAL_RGB[2] = 0; 

     METALLOID_RGB = new double[3]; 
     METALLOID_RGB[0] = 0.866666667; //221/255 
     METALLOID_RGB[1] = 0.62745098; //160/255 
     METALLOID_RGB[2] = 0.866666667; //221/255 

     RECENT_RGB = new double[3]; 
     RECENT_RGB[0] = 0.803921569; //205/255 
     RECENT_RGB[1] = 0.788235294; //201/255 
     RECENT_RGB[2] = 0.788235294; //201/255 
    } 

    @Override 
    void render() { 
     GL11.glDisable(GL11.GL_TEXTURE_2D); 
     GL11.glDisable(GL11.GL_BLEND); 
     for(int x=0;x<elements.length;x++) 
      elements[x].render(); 
     GL11.glEnable(GL11.GL_TEXTURE_2D); 
     GL11.glEnable(GL11.GL_BLEND); 
     for(int x=0;x<elements.length;x++) 
      elements[x].renderWithTex(); 
    } 

    @Override 
    void tick() { 
     for(int x=0;x<elements.length;x++) 
      elements[x].tick(); 
    } 

    @Override 
    public void updateInput(Vector2D mousePos) 
    { 
     this.mousePos = mousePos; 
     for(int x=0;x<elements.length;x++) 
     { 
      if(mousePos.isInBoundsWithDim(elements[x].pos.x, elements[x].pos.y, elements[x].dim.x, elements[x].dim.y)) 
       elements[x].isSelected = true; 
      else 
       elements[x].isSelected = false; 
     } 
    } 

    @Override 
    void onEntityClicked() { 
     for(int x=0;x<elements.length;x++) 
     { 
      if(mousePos.isInBoundsWithDim(elements[x].pos.x, elements[x].pos.y, elements[x].dim.x, elements[x].dim.y)) 
       elements[x].onEntityClicked(); 
     } 
    } 

} 

EntityElement:

package com.flafla2.periodicTable; 

import org.lwjgl.opengl.GL11; 

public class EntityElement extends ClickableEntity { 

    String symbol; 
    String element; 
    int atomicNumber; 
    EntityPeriodicTable table; 
    int state;//0=solid, 1=liquid, 2=gas 
    int metalState;//0=metal, 1=metalloid, 2=nonmetal, 3=discovered recently 
    Vector2D gridPos; 

    public EntityElement(int an, int st, int ms, String sy, String en, Vector2D gp, EntityPeriodicTable pt) 
    { 
     symbol = sy; 
     element = en; 
     atomicNumber = an; 
     table = pt; 
     state = st; 
     metalState = ms; 
     gridPos = gp; 

     dim.x = table.ELEMENT_SIZE; dim.y = table.ELEMENT_SIZE; 
     pos.x = table.pos.x + table.ELEMENT_SIZE*(gridPos.x-1); pos.y = table.pos.y + table.ELEMENT_SIZE*(gridPos.y-1); 
    } 

    public double[] getStateColor() 
    { 
     switch(state) 
     { 
     case 0: 
      return table.SOLID_RGB; 
     case 1: 
      return table.LIQUID_RGB; 
     case 2: 
      return table.GAS_RGB; 
     default: 
      double[] d = {0.0d,0.0d,0.0d}; 
      return d; 
     } 
    } 

    public double[] getMetalColor() 
    { 
     switch(metalState) 
     { 
     case 0: 
      return table.METAL_RGB; 
     case 1: 
      return table.METALLOID_RGB; 
     case 2: 
      return table.NONMETAL_RGB; 
     case 3: 
      return table.RECENT_RGB; 
     default: 
      double[] d = {0.0d,0.0d,0.0d}; 
      return d; 
     } 
    } 

    @Override 
    void render() { 
     GL11.glPushMatrix(); 
      GL11.glTranslatef(pos.x, pos.y, 0); 
      double[] d = getMetalColor(); 
      GL11.glColor3d(d[0], d[1], d[2]); 
      GL11.glBegin(GL11.GL_QUADS); 
      { 
       GL11.glVertex2f(0, 0);//topleft 
       GL11.glVertex2f(dim.x, 0);//topright 
       GL11.glVertex2f(dim.x, dim.y);//bottomright 
       GL11.glVertex2f(0, dim.y);//bottomleft 
      } 
      GL11.glEnd(); 
      GL11.glColor3d(1.0d, 1.0d, 1.0d); 
     GL11.glPopMatrix(); 
    } 

    public void renderWithTex() 
    { 
     Font.drawString(symbol, new Vector2D(pos.x+dim.x/2-Font.getStringWidth(symbol,2)/2,pos.y+dim.y/2-Font.FONT_HEIGHT), 2); 
    } 

    @Override 
    void tick() { 
     if(isSelected) 
     { 
      dim.x = table.ELEMENT_SIZE+6; dim.y = table.ELEMENT_SIZE+6; 
      pos.x = table.pos.x + table.ELEMENT_SIZE*(gridPos.x-1)-3; pos.y = table.pos.y + table.ELEMENT_SIZE*(gridPos.y-1)-3; 
     } else 
     { 
      dim.x = table.ELEMENT_SIZE; dim.y = table.ELEMENT_SIZE; 
      pos.x = table.pos.x + table.ELEMENT_SIZE*(gridPos.x-1); pos.y = table.pos.y + table.ELEMENT_SIZE*(gridPos.y-1); 
     } 
    } 

    @Override 
    void onEntityClicked() { 

    } 

} 

(コードが未完成であるレンダー)テーブル上の特定の要素のデータを保持し、それをレンダリングするフォント:

package com.flafla2.periodicTable; 

import java.awt.image.BufferedImage; 

import javax.imageio.ImageIO; 

import org.lwjgl.opengl.GL11; 

public class Font { 
    public static final String fontText = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz:;?!\"&',-.[]#()+ "; 
    public static final BufferedImage fontSheet = TextureLoader.loadTexture("/res/text.png"); 

    public static final int FONT_WIDTH = 9; 
    public static final int FONT_HEIGHT = 8; 

    public static void drawString(String s, Vector2D pos, float dim) 
    { 
     drawString(s,pos,new Vector2D((int)Math.floor(dim*FONT_WIDTH),(int)Math.floor(dim*FONT_HEIGHT))); 
    } 

    public static void drawString(String s, Vector2D pos) 
    { 
     drawString(s,pos,new Vector2D(9,8)); 
    } 

    public static void drawString(String s, Vector2D pos, Vector2D dim) 
    { 
     for(int x=0;x<s.length();x++) 
     { 
      drawLetter(s.charAt(x),new Vector2D(pos.x+dim.x*x,pos.y),dim); 
     } 
    } 

    public static int getStringWidth(String s) 
    { 
     return s.length()*FONT_WIDTH; 
    } 

    public static int getStringWidth(String s,float f) 
    { 
     return (int)Math.floor(s.length()*FONT_WIDTH*f); 
    } 

    public static Vector2D getPosOfLetterOnImg(Character c,int gridNumb) 
    { 
     int xOffset = 0; 
     int yOffset = 0; 
     if(!c.equals(' ')) 
     { 
      int letterNumb = fontText.indexOf(c); 
      xOffset = (letterNumb%26)*FONT_WIDTH; 
      if(xOffset != 0) 
       xOffset -=1; 
      yOffset = 0; 
      int yGridOffset = (letterNumb < 26) ? 0 : ((letterNumb < 52) ? 1 : 2); 

      switch(gridNumb) 
      { 
      case 1: 
       yOffset = 34; 
       break; 
      case 2: 
       yOffset = 69; 
       break; 
      default: 
       yOffset = 0; 
      } 

      for(int x=0;x<yGridOffset;x++) 
       yOffset += FONT_HEIGHT+x+3; 
     } else 
     { 
      xOffset = 235; 
      yOffset = 92; 
     } 

     return new Vector2D(xOffset,yOffset); 
    } 

    public static void drawLetter(Character c, Vector2D pos, Vector2D dim) 
    { 
     if(fontSheet == null) 
      return; 

     Vector2D letterPos = getPosOfLetterOnImg(c,2); 

     BufferedImage letterImage = fontSheet.getSubimage(letterPos.x, letterPos.y, FONT_WIDTH, FONT_HEIGHT); 
     int textureID = TextureLoader.loadGLTexture(letterImage); 
     letterImage = null; 

     GL11.glPushMatrix(); 
      GL11.glTranslatef(pos.x, pos.y, 0); 
      GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID); 
      GL11.glBegin(GL11.GL_QUADS); 
      { 
       GL11.glTexCoord2f(0, 0); 
       GL11.glVertex2f(0, 0); 

       GL11.glTexCoord2f(1, 0); 
       GL11.glVertex2f(dim.x, 0); 

       GL11.glTexCoord2f(1, 1); 
       GL11.glVertex2f(dim.x, dim.y); 

       GL11.glTexCoord2f(0, 1); 
       GL11.glVertex2f(0, dim.y); 
      } 
      GL11.glEnd(); 
     GL11.glPopMatrix(); 
    } 
} 

TextureLoader:ハンドルは、テキスト画面上にレンダリング:テクスチャをロードする(duh lol)

package com.flafla2.periodicTable; 

import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.nio.ByteBuffer; 

import javax.imageio.ImageIO; 

import org.lwjgl.BufferUtils; 
import org.lwjgl.opengl.GL11; 
import org.lwjgl.opengl.GL12; 

public class TextureLoader { 
    public static BufferedImage loadTexture(String texturePath) 
    { 
     try { 
      return ImageIO.read(PeriodicTable.class.getResource(texturePath)); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    private static final int BYTES_PER_PIXEL = 4; 
    public static int loadGLTexture(BufferedImage image){ 
     int[] pixels = new int[image.getWidth() * image.getHeight()]; 
     image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth()); 

     ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * BYTES_PER_PIXEL); //4 for RGBA, 3 for RGB 

     for(int y = 0; y < image.getHeight(); y++){ 
      for(int x = 0; x < image.getWidth(); x++){ 
       int pixel = pixels[y * image.getWidth() + x]; 
       buffer.put((byte) ((pixel >> 16) & 0xFF));  // Red component 
       buffer.put((byte) ((pixel >> 8) & 0xFF));  // Green component 
       buffer.put((byte) (pixel & 0xFF));    // Blue component 
       buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component. Only for RGBA 
      } 
     } 

     buffer.flip(); //FOR THE LOVE OF GOD DO NOT FORGET THIS 

     // You now have a ByteBuffer filled with the color data of each pixel. 
     // Now just create a texture ID and bind it. Then you can load it using 
     // whatever OpenGL method you want, for example: 

     int textureID = GL11.glGenTextures(); //Generate texture ID 
     GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID); //Bind texture ID 

     //Setup wrap mode 
     GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); 
     GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); 

     //Setup texture scaling filtering 
     GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); 
     GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); 

     //Send texel data to OpenGL 
     GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); 
     buffer = null; 

     //Return the texture ID so we can bind it later again 
     return textureID; 
    } 
} 

私は知っている、それは多くのコードですが、誰かが私を助けることができれば大いに感謝するでしょう。

ありがとう、Flafla2。

+2

あなたはメモリリークを言う、あなたは利用状況を見てみましたか?あなたはベクトルをたくさん新しくしています。これは普通で罰金ですが、それは私が見ている最初の場所です。可能であれば、CPUとメモリの使用状況をプロファイリングして、ホットスポットの位置を確認してください。ただし、CPU *上でレンダリングコード*をプロファイリングすると、間違ったデータが提供され、ほとんど無視されるはずです(ドライバ/カードバッファはCPUプロファイルが一致しないようにバッファします)。 – ssube

+0

ありがとう、私は今プロファイリングしようとする(前にプロファイラに問題があった、私は問題を解決することができますが表示されます)。 – Flafla2

+1

申し訳ありませんが、問題が見つかりました。 'TextureLoader.java'では、' glDeleteTextures(textureID) 'を使わなかったので、' Font.java'で使われたテクスチャはメモリからアンロードされていませんでした。今、私は安定した50 + fpsを取得しています(私の馬鹿げたMacbookで、もちろん)。あなたの助けをありがとう! – Flafla2

答えて

1

申し訳ありませんが、問題が見つかりました。

TextureLoader.javaでは、glDeleteTextures(textureID)を使用しなかったため、Font.javaで使用されていたテクスチャはメモリからアンロードされませんでした。今、私は安定した50 + fpsを取得しています(私の馬鹿げたMacbookで、もちろん)。

また、もう1つの確認された回答がfpsを~60に押し上げました。誰もが疑問に思っている場合は、ここで新しいdrawLetter()方法が変化して、次のとおりです。

public static void drawLetter(Character c, Vector2D pos, Vector2D dim) 
    { 
     if(fontSheet == null) 
      return; 

     Vector2D letterPos = getPosOfLetterOnImg(c,2); 

     //BufferedImage letterImage = fontSheet.getSubimage(letterPos.x, letterPos.y, FONT_WIDTH, FONT_HEIGHT); 
     //int textureID = TextureLoader.loadGLTexture(letterImage); 
     //letterImage = null; 

     int width = fontSheet.getWidth(); int height = fontSheet.getHeight(); 
     double d[] = {(double)letterPos.x/width, (double)letterPos.y/height, (double)(letterPos.x+FONT_WIDTH)/width, (double)(letterPos.y+FONT_HEIGHT)/height}; 
     GL11.glPushMatrix(); 
      GL11.glTranslatef(pos.x, pos.y, 0); 
      GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID); 
      GL11.glBegin(GL11.GL_QUADS); 
      { 
       GL11.glTexCoord2d(d[0], d[1]); 
       GL11.glVertex2f(0, 0); 

       GL11.glTexCoord2d(d[2], d[1]); 
       GL11.glVertex2f(dim.x, 0); 

       GL11.glTexCoord2d(d[2], d[3]); 
       GL11.glVertex2f(dim.x, dim.y); 

       GL11.glTexCoord2d(d[0], d[3]); 
       GL11.glVertex2f(0, dim.y); 
      } 
      GL11.glEnd(); 
     GL11.glPopMatrix(); 

     //GL11.glDeleteTextures(textureID); 
    } 
1

あなたはすでにそれを改善して改善の余地があると思っていました。私はあなたがイメージにあなたのフォントを持っていることを見て、あなたが描画したいそれぞれの文字のために、その文字でイメージの一部をテクスチャにロードし、その後すべてをクリーンアップする必要がある。

イメージ全体を1つの大きなテクスチャにロードする方が、プログラム中にそのテクスチャを保持し、各フレームのレンダリング時に再利用する方がよい。正しいテクスチャ座標を指定することで、レンダリングする文字を選択することができます。

あなたのMacBookが本当に古くない限り、CPU使用率が低い60fpsのキャップを打つことができるはずです。

+0

ありがとう、それは〜30から〜60に私のFPSをもたらした! – Flafla2

関連する問題