# Power of Two empty space



## javaPanther (18. Dez 2011)

Hallo liebe Leute,
da in meinem jetzigen Projekt jedes eingesparte Megabyte an Assets enorm viel Wert ist habe ich mich daran versucht statt der POT-Texturen auf die genaueren Texturen umzuschwenken um Speicherplatz zu sparen. 

Bei meiner Variante versuche ich die Bilder aus den Assets in eine POT-Texture während des Ladeprozesses umzuwandeln. Dies klappt soweit auch ganz gut, allerdings wird nicht die gesamte Textur benutzt sondern nur der Teil der den originalen Maßen entspricht. Der Rest der Textur bleibt schwarz.

Innerhalb des Beispiels wird das Problem mit der Textur über die Texturkoordinaten gelöst, allerdings funktioniert das in meinem Fall nicht, da ich auch GL_REPEAT verwenden möchte, was mit Texturabschnitten nicht funktioniert.

"Mein" Code den ich aus dem Spaceinvaders Tutorial habe:

```
public Texture getTexture(String resourceName, 
                              int target, 
                              int dstPixelFormat, 
                              int minFilter, 
                              int magFilter, int textureFormat) throws IOException 
    { 
        int srcPixelFormat = 0;
        
        // create the texture ID for this texture 

        int textureID = createTextureID(); 
        Texture texture = new Texture(target,textureID); 
        
        // bind this texture 

        GL11.glBindTexture(target, textureID); 
 
        BufferedImage bufferedImage = loadImage(resourceName); 
        texture.setWidth(bufferedImage.getWidth());
        texture.setHeight(bufferedImage.getHeight());
        
        if (bufferedImage.getColorModel().hasAlpha()) {
            srcPixelFormat = GL11.GL_RGBA;
        } else {
            srcPixelFormat = GL11.GL_RGB;
        }

        // convert that image into a byte buffer of texture data 

        ByteBuffer textureBuffer = convertImageData(bufferedImage,texture); 
        
        if (target == GL11.GL_TEXTURE_2D) 
        { 
            GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, minFilter); 
            GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, magFilter);
            GL11.glTexParameterf( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, textureFormat );
            GL11.glTexParameterf( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, textureFormat );
        } 
 
        // produce a texture from the byte buffer

        GL11.glTexImage2D(target, 
                      0, 
                      dstPixelFormat, 
                      get2Fold(bufferedImage.getWidth()), 
                      get2Fold(bufferedImage.getHeight()), 
                      0, 
                      srcPixelFormat, 
                      GL11.GL_UNSIGNED_BYTE, 
                      textureBuffer ); 
        
        return texture; 
    } 
    
    /**
     * Get the closest greater power of 2 to the fold number
     * 
     * @param fold The target number
     * @return The power of 2
     */
    private int get2Fold(int fold) {
        int ret = 2;
        while (ret < fold) {
            ret *= 2;
        }
        return ret;
    } 
    
    /**
     * Convert the buffered image to a texture
     *
     * @param bufferedImage The image to convert to a texture
     * @param texture The texture to store the data into
     * @return A buffer containing the data
     */
    private ByteBuffer convertImageData(BufferedImage bufferedImage,Texture texture) { 
        ByteBuffer imageBuffer = null; 
        WritableRaster raster;
        BufferedImage texImage;
        
        int texWidth = 2;
        int texHeight = 2;
        
        // find the closest power of 2 for the width and height

        // of the produced texture

        while (texWidth < bufferedImage.getWidth()) {
            texWidth *= 2;
        }
        while (texHeight < bufferedImage.getHeight()) {
            texHeight *= 2;
        }
        
        texture.setTextureHeight(texHeight);
        texture.setTextureWidth(texWidth);
        
        // create a raster that can be used by OpenGL as a source

        // for a texture

        if (bufferedImage.getColorModel().hasAlpha()) {
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,texWidth,texHeight,4,null);
            texImage = new BufferedImage(glAlphaColorModel,raster,false,new Hashtable());
        } else {
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,texWidth,texHeight,3,null);
            texImage = new BufferedImage(glColorModel,raster,false,new Hashtable());
        }
            
        // copy the source image into the produced image

        Graphics g = texImage.getGraphics();
        g.setColor(new Color(0f,0f,0f,0f));
        g.fillRect(0,0,texWidth,texHeight);
        g.drawImage(bufferedImage,0,0,null);
        
        // build a byte buffer from the temporary image 

        // that be used by OpenGL to produce a texture.

        byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer()).getData(); 

        imageBuffer = ByteBuffer.allocateDirect(data.length); 
        imageBuffer.order(ByteOrder.nativeOrder()); 
        imageBuffer.put(data, 0, data.length); 
        imageBuffer.flip();
        
        return imageBuffer; 
    }
```

Ich hoffe mal dass die Lösung genauso trivial wie die Frage ist ^^

Grüße und Dank im Voraus!


----------



## Marco13 (18. Dez 2011)

Hab' den Code jetzt nicht ganz nachvollzogen, würde aber tippen, dass dort irgendwo die Zeile
g.drawImage(bufferedImage,0,0,*powerOfTwoWidth, powerOfTwoHeight,* null);
vorkommen müßte...


----------



## Guest2 (18. Dez 2011)

Moin,

habe den Code ebenfalls nicht Nachvollzogen (), aber brauchst Du den überhaupt noch POT Texturen? Deine restlichen OpenGL Fragen wirkten nicht, als ob Du für Steinzeithartware schreiben würdest?

Viele Grüße,
Fancy


----------



## javaPanther (18. Dez 2011)

Danke für die Antwort die ich direkt als Lösung verwenden konnte.

Ich arbeite derzeit an verschiedenen Projekten die sich teilweise in ihren Funktionen überschneiden. Das gemeinsame Ziel / Fluch ist, dass die Programme auf möglichst vielen "geeigneten" Plattformen zu verbreiten.

Hierzu zählen Desktop, Android, Xbox und iOS (in absteigender zeitlicher Reihenfolge). Da insbesondere die Android Plattform zu starker Variation in der Hardware neigt wollte ich möglichst niedrige Anforderungen als Basis festlegen. Falls hierfür noch Anregungen da sind würde ich das gerne erfahren.


----------



## Guest2 (18. Dez 2011)

Nuja, auf dem Desktop dürftest Du mit OpenGL 2.1 schon eine relativ große Basis erreichen. Android (imho ab 2.2) und iOS unterstützen OpenGL ES 2.0. Bei der XBox dachte ich immer das die nur Direct3D kann?

Um ein bissel fummeln beim portieren wirst Du also so oder so nicht umhinkommen 

Viele Grüße,
Fancy


----------

