OpenGl Texterstellung

Jhue89

Bekanntes Mitglied
Guten Morgen Zusammen,
ich bins schon wieder.

ich hab folgendes Problem und komme nicht mehr weiter.

ich möchte in meiner Zeichnung einige Texte anzeigen lassen. So wie ich es gelesen haben, kann ich mit Android/OpenGL Texte nur Zeichen.
Also gibt es nach meinem Verständnis nur 2 Wege um das hinzubekommen.

1. Ich Zeichen tätsächlich jeden einzelnen Buchstaben. Das ist aber glaub ich recht müßig.
2. Ich erstelle mir ein Bitmap nutze die Canvas methode
Java:
  canvas.drawText(text, x1, y1, paint);
und Zeichne das Bitmap in die Oberfläche.

Java:
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.opengl.GLUtils;
import javax.microedition.khronos.opengles.GL10;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class OpenGLTextRenderer {
    private static final int TEXTURE_WIDTH = 256;
    private static final int TEXTURE_HEIGHT = 256;

    private Bitmap textBitmap;
    private int[] textures = new int[1];

    public OpenGLTextRenderer() {
       textBitmap = Bitmap.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);

    }

    public void loadTexture(GL10 gl) {
        gl.glGenTextures(1, textures, 0);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, textBitmap, 0);
    }

 
    public void renderText(GL10 gl, String text, float x, float y, int textSize) {
        if (textBitmap == null || textBitmap.isRecycled()) {
            textBitmap = Bitmap.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);
        } else {
            textBitmap.eraseColor(Color.TRANSPARENT);
        }

        Canvas canvas = new Canvas(textBitmap);

        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawPaint(paint);

        paint.setColor(Color.BLACK);
        paint.setTextSize(textSize * 10);

        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        int x1 = (textBitmap.getWidth() - bounds.width()) / 2;
        int y1 = (textBitmap.getHeight() + bounds.height()) / 2;

        canvas.drawText(text, x1, y1, paint);
        GLUtils.texSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, textBitmap);

        float[] vertices = {
                x, y, 0.0f,
                x + textBitmap.getWidth(), y, 0.0f,
                x, y + textBitmap.getHeight(), 0.0f,
                x + textBitmap.getWidth(), y + textBitmap.getHeight(), 0.0f
        };

        float[] textureCoordinates = {
                1.0f, 0.0f,
                1.0f, 1.0f,
                0.0f, 0.0f,
                0.0f, 1.0f
        };

        ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
        vertexBuffer.order(ByteOrder.nativeOrder());
        FloatBuffer vertexFloatBuffer = vertexBuffer.asFloatBuffer();
        vertexFloatBuffer.put(vertices);
        vertexFloatBuffer.position(0);

        ByteBuffer textureBuffer = ByteBuffer.allocateDirect(textureCoordinates.length * 4);
        textureBuffer.order(ByteOrder.nativeOrder());
        FloatBuffer textureFloatBuffer = textureBuffer.asFloatBuffer();
        textureFloatBuffer.put(textureCoordinates);
        textureFloatBuffer.position(0);

        gl.glEnable(GL10.GL_TEXTURE_2D);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glColor4f(1f, 1f, 1f, 0f);

        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexFloatBuffer);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureFloatBuffer);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glDisable(GL10.GL_TEXTURE_2D);
      //  textBitmap.recycle();
    }


}

Ich hab mich für 2 entschieden. Leider laufe ich hier auf Probleme mit der Speicherauslastung.
Der Text wird dargestellt zwar noch auf dem Kopf, aber da muss ich an den Koordinaten noch basteln. Nach einer gewissen Zeit schmiert mir die App ab. Ich tippe auf den Speicher, ich bekomme aber keine Fehlerausgabe oder ähnliches.

Durch den Oberen Teile wollte ich eigentlich das bereits vorhanden Bitmap immer wieder Verwenden, um nicht unnötig viele Objekte zu erzeugen.

Leider geht mein Plan an der Stelle nicht auf. Was kann ich noch machen? oder was mache ich Falsch?


Nachtrag:

Diese Meldung bekomme ich kurz vorher:
I/art: Background sticky concurrent mark sweep GC freed 144105(7MB) AllocSpace objects, 0(0B) LOS objects, 20% free, 27MB/34MB, paused 2.040ms total 101.390ms
 
Zuletzt bearbeitet:

KonradN

Super-Moderator
Mitarbeiter
Die Lösung dürfte ganz einfach sein: Du erzeugst Dir eine Bitmap mit der gewünschten Schrift und dann nutzt Du OpenGL nur noch, um diese Bitmap zu rendern.

Dazu kannst Du auf zwei Wegen vorgehen:

a) Uralt Ansatz, wie er früher in Spielen verwendet wurde (Da hatte man dann den Namen "Sprites" für solche kleinen Bitmaps):
  • Du erstellst Dir eine Bitmap mit allen Zeichen, die Du brauchst. Also jedes Zeichen hat eine bestimmte Größe dx/dy und dann kennst Du den Index, wo es ist.
  • Wenn Du einen Buchstaben brauchst, dann malst Du einfach den Ausschnitt der Bitmap an der gewünschten Stelle. Wenn den Index x,y kennst, dann sind die Koordinaten der Bitmap x * dx, y * dy und natürlich Breite / Höhe dx/dy.

Generell musst Du schauen, welche Größen Du brauchst und wie es aussieht, wenn Du die Bitmap skallierst. Das kann unschön sein. Also evtl. lieber großes dy / dy und dann kleiner darstellen um zu große Pixeleffekte zu vermeiden.

Und natürlich auch auf die Lizenz der Schriften achten - nicht dass Du eine Schriftart verwendest, die so nicht verwendet werden darf. Aber das erklärt sich ja von alleine.

Diesen Ansatz würde ich aber nur verwenden, wenn ich einen RetroLook haben wollte denke ich.

b) Einfacher kann es sein, Bitmap / Canvas zu nutzen, um eine Bitmap mit dem gewünschten Text zu haben.

Generell wäre es evtl. für Dich interessant, Dir einmal ChatGPT anzusehen. Für so typische Fragen bietet ChatGPT durchaus gute Antworten incl. Code. Ok, die Idee unter a) wird man da nur bei explizitem Wunsch bekommen denke ich mal, aber ich denke, der Ansatz b) ist, was Du willst.
 

Jhue89

Bekanntes Mitglied
Hey! Danke für eure antworten

Was soll ich Sagen ChatGPT habe ich nebenbei am laufen. Ein Super Helferlei!
Aber an dieser stelle bekomme ich nichts mehr vernüftiges raus.

Die Idee ein Bitmap zu erstellen und anschließend mit Canvas die Schrift zu erzeugen stammt aus dem Chat.

Rein Logisch sollte meine Lösung funktionieren. Das Canvas Objekt erzeuge ich jetzt auch nur einmalig.

ich hab bestimmt irgend wo noch eine Zeile drin die den GL ärgert.

Java:
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.opengl.GLUtils;
import javax.microedition.khronos.opengles.GL10;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class OpenGLTextRenderer {
    private static final int TEXTURE_WIDTH = 80;
    private static final int TEXTURE_HEIGHT = 80;

    private Bitmap textBitmap;
    private int[] textures = new int[1];

    private Canvas mCanvas;

    public OpenGLTextRenderer() {
       textBitmap = Bitmap.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(textBitmap);

    }

    public void loadTexture(GL10 gl) {
        gl.glGenTextures(1, textures, 0);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

   //     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, textBitmap, 0);
    }

 

    public void renderText(GL10 gl, String text, float x, float y, int textSize) {
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, textBitmap, 0);
        if (textBitmap == null || textBitmap.isRecycled()) {
            textBitmap = Bitmap.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(textBitmap);
        } else {
            textBitmap.eraseColor(Color.TRANSPARENT);
            mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

        }

    //    Canvas canvas = new Canvas(textBitmap); wir behalten das Canvas objekt



        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.FILL);
        mCanvas.drawPaint(paint);

        paint.setColor(Color.BLACK);
        paint.setTextSize(textSize * 10);

        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        int x1 = (textBitmap.getWidth() - bounds.width()) / 2;
        int y1 = (textBitmap.getHeight() + bounds.height()) / 2;

        mCanvas.drawText(text, x1, y1, paint);
        GLUtils.texSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, textBitmap);

        float[] vertices = {
                x, y, 0.0f,
                x + textBitmap.getWidth(), y, 0.0f,
                x, y + textBitmap.getHeight(), 0.0f,
                x + textBitmap.getWidth(), y + textBitmap.getHeight(), 0.0f
        };
      // 90 Grad
      //  float[] textureCoordinates = {
      //
      //          0.0f, 0.0f,
      //          0.0f, 1.0f,
      //          1.0f, 0.0f,
      //          1.0f, 1.0f
      //  };
        //0 Grad
        float[] textureCoordinates = {

                0.0f, 1.0f,
                1.0f, 1.0f,
                0.0f, 0.0f,
                1.0f, 0.0f
        };

        ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
        vertexBuffer.order(ByteOrder.nativeOrder());
        FloatBuffer vertexFloatBuffer = vertexBuffer.asFloatBuffer();
        vertexFloatBuffer.put(vertices);
        vertexFloatBuffer.position(0);

        ByteBuffer textureBuffer = ByteBuffer.allocateDirect(textureCoordinates.length * 4);
        textureBuffer.order(ByteOrder.nativeOrder());
        FloatBuffer textureFloatBuffer = textureBuffer.asFloatBuffer();
        textureFloatBuffer.put(textureCoordinates);
        textureFloatBuffer.position(0);

        gl.glEnable(GL10.GL_TEXTURE_2D);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glColor4f(1f, 1f, 1f, 1f);

        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexFloatBuffer);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureFloatBuffer);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glDisable(GL10.GL_TEXTURE_2D);
      //  textBitmap.recycle();
    }


}
 

Ähnliche Java Themen

Neue Themen


Oben