# LWJGL - Bild rendern



## lumo (15. Sep 2010)

Hallo,

ich möchte gerade in meiner freizeit ein spiel entwickeln (ganz was simples  )
(ich hab bis jetzt mit opengl nur einen 3d modell loader programmiert in c)

nun will ich das spiel aber in java programmieren (ev. später noch in c umsetzen)

was ich in meinem spiel benötige ist:
ich muss ein bild laden und in echtzeit bearbeiten können (pixel für pixel)
habe das jetzt einmal versucht als vertex array zu lösen, allerdings werden die punkte nicht schön, ohne artefakte dazwischen gerendert. (in form von linien)

nun hab ich versucht aus einigen tutorials mir informationen zusammenzutragen, wie ich das lösen kann.

ein ansatz war render to texture, allerdings hab ich es nicht hinbekommen eine textur zu laden...
ich bin beim FrameBufferObject erstellen schon gescheitert...

hab meinen algorithmus, der das bild verändert schon in labels getestet (liegt also nicht am verarbeiten der daten sondern am richtigen drehen an LWJGL)

wenn jemand mir ein einfaches beispiel zur verfügung stellen könnte wäre ich heilfroh! (oder ein link zu einem KLEINEN programm das ein bild lädt und das im speicher verändert wird und dann neu gerendert wird...)

DANKE schon mal im voraus

EDIT: würdet ihr mir eher zu JOGL2 raten? (das ist nur mal ne frage nebenbei )


----------



## Empire Phoenix (15. Sep 2010)

Für ein spiel würde ich zu eienr engine raten, jmonkey, jcpirgetwas oder andor3d oder so spaart dir ne ganze menge kram


----------



## Marco13 (15. Sep 2010)

Hm. Für ein "simples" Spiel, wo es (der beschreibung nach) in erster Linie darum geht, ein Bild darzustellen, wäre JME vielleicht gar nicht mal so geeignet wie z.B. ein "einfaches" glDrawPixels in LWJGL. Falls das nicht irgendjemand anderes für mich erledigt (zwinker, zwinker) kann ich morgen mal versuchen, ein KSKB dazu zu basteln.


----------



## lumo (15. Sep 2010)

eine engine brauch ich gar nicht. Denn es werden nur bilder angezeigt und einfache mausklicks ausgeführt. (ich muss nur die position des mausklicks rausfinden - aber das versuche ich, wenn das problem des bildes gelöst ist )


----------



## Empire Phoenix (16. Sep 2010)

Bleibt die frage wozu dann lwjgl? würde auch alles mit swing gehen und is einfacherer damit. (Ausserdem ist es dann pure java und ohne weitere abhängigkeiten)


----------



## lumo (16. Sep 2010)

ganz einfach,
wenn ichs dann in c umsetzen will muss ich mir nicht wieder nen kopf machen, wie ich 2d/3d-graphiken implementiere 

opengl ist auch plattformunabhängig... (die anwendung muss halt neu compiliert werden)
läuft aber dann auch auf smartphones OHNE java (iPhone)

@Marco13 ein KSKB wäre natürlich super! :toll:


----------



## Marco13 (16. Sep 2010)

Du kannst dir das Beispiel auf

http://www.too-late.de/lwjgl-2d.zip

runterladen.

:joke:

Schon gut, hier ist es: Läd ein Bild "image.jpg", zeigt es an und bewegt es ein bißchen rum. Aber es stimmt schon: Es könnte sogar sein, dass das allein mit reinem Swing schneller ist - Swing verwendet nämlich intern _auch_ OpenGL, und bei LWJGL muss man das erst in einen direct buffer kopieren und so... Ein BufferedImage, das einen direct buffer im Hintergrund hat, hatte ich zwar auch mal gebastelt, aber das ist (noch) nicht veröffentlichbar.

```
import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.AWTGLCanvas;
import org.lwjgl.opengl.GL11;


class ImageCanvas extends AWTGLCanvas
{
    private Point imagePosition = new Point(0,0);
    private BufferedImage bufferedImage = null;
    private IntBuffer buffer = null;
    
    public ImageCanvas() throws LWJGLException
    {
    }
    
    public void paintGL()
    {
        render();
        try
        {
            swapBuffers();
        }
        catch (LWJGLException e)
        {
            e.printStackTrace();
        }
    }
    
    public void setBufferedImage(BufferedImage bufferedImage)
    {
        this.bufferedImage = bufferedImage;
        int w = bufferedImage.getWidth();
        int h = bufferedImage.getHeight();
        buffer = ByteBuffer.allocateDirect(w*h*4).
            order(ByteOrder.nativeOrder()).asIntBuffer();
        updateImageBuffer();
    }
    
    private void updateImageBuffer()
    {
        Raster raster = bufferedImage.getRaster();
        DataBuffer dataBuffer = raster.getDataBuffer();
        if (!(dataBuffer instanceof DataBufferInt))
        {
            throw new IllegalArgumentException(
                "TYPE_INT_BGR image required");
        }
        DataBufferInt dataBufferInt = (DataBufferInt)dataBuffer;
        int data[] = dataBufferInt.getData();
        
        buffer.put(data);
        buffer.rewind();
    }
    
    public void setImagePosition(int x, int y)
    {
        imagePosition.x = x;
        imagePosition.y = y;
        repaint();
    }
    
    private void render()
    {
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glLoadIdentity();
        GL11.glOrtho(0,getWidth(),0,getHeight(),-2,2);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glLoadIdentity();

        GL11.glClearColor(0,0,0,0);
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
        
        int w = bufferedImage.getWidth();
        int h = bufferedImage.getHeight();
        int format = GL11.GL_RGBA;
        int type = GL11.GL_UNSIGNED_BYTE;
        
        GL11.glRasterPos4i(imagePosition.x, imagePosition.y, 0, 1);
        GL11.glDrawPixels(w, h, format, type, buffer);
    }
}



public class LWJGL2DTest 
{
    public static void main(String[] arguments) 
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            
            @Override
            public void run()
            {
                try
                {
                    new LWJGL2DTest();
                }
                catch (LWJGLException e)
                {
                    e.printStackTrace();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        });
        
    }
    
    public LWJGL2DTest() throws LWJGLException, IOException
    {
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        final ImageCanvas imageCanvas = new ImageCanvas();
        final BufferedImage bufferedImage = loadImage("image.jpg");
        imageCanvas.setBufferedImage(bufferedImage);
        
        Thread thread = new Thread(new Runnable()
        {
            double a = 0;
            @Override
            public void run()
            {
                while (true)
                {
                    int cx = imageCanvas.getWidth() / 2 - 
                        bufferedImage.getWidth() / 2;
                    int cy = imageCanvas.getHeight() / 2 - 
                        bufferedImage.getHeight() / 2;
                    int d = 50;
                    double x = cx + d * Math.cos(a);
                    double y = cy + d * Math.sin(a);
                    imageCanvas.setImagePosition((int)x, (int)y);
                    a += 0.1;
                    try
                    {
                        Thread.sleep(10);
                    }
                    catch (InterruptedException e)
                    {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });
        thread.start();
        
        
        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(imageCanvas, BorderLayout.CENTER);
        frame.setSize(800,800);
        frame.setVisible(true);
    }
    
    
    private static BufferedImage loadImage(String fileName) throws IOException
    {
        BufferedImage bufferedImage = ImageIO.read(new File(fileName));
        
        BufferedImage result = new BufferedImage(
            bufferedImage.getWidth(), 
            bufferedImage.getHeight(), 
            BufferedImage.TYPE_INT_BGR);
        Graphics2D g = result.createGraphics();
        g.scale(1,-1);
        g.drawImage(bufferedImage, 0, -bufferedImage.getHeight(),null);
        g.dispose();
        return result;
    }
    
}
```


----------



## Guest2 (16. Sep 2010)

Moin,



Marco13 hat gesagt.:


> Du kannst dir das Beispiel auf
> 
> http://www.too-late.de/lwjgl-2d.zip
> 
> ...



Lol, ich dachte schon, ich hätte was verpasst. 




Marco13 hat gesagt.:


> Schon gut, hier ist es: Läd ein Bild "image.jpg", zeigt es an und bewegt es ein bißchen rum. Aber es stimmt schon: Es könnte sogar sein, dass das allein mit reinem Swing schneller ist



Vor allem, da lumo angibt es mit OpenGL machen zu wollen, damit es leichter portierbar sei. Allerdings ist für die eigentliche Anzeige des Bildes nur eine Zeile verantwortlich. Der Rest ist praktisch nur "Fensterhandling" und das wäre z.B. unter C eh anders (und für jedes OS auch wieder anders).

Imho, wenn man OpenGL nutzt, sollte man der Grafikkarte auch was zu tun geben. 

(Immer wenn ich 2D höre, denk ich an tiles, was mich dann wieder an irgendeiner Variation vom dem hier erinnert.)




Marco13 hat gesagt.:


> Ein BufferedImage, das einen direct buffer im Hintergrund hat, hatte ich zwar auch mal gebastelt, aber das ist (noch) nicht veröffentlichbar.



Direkt, also ohne das was umkopiert wird? Dann bin ich drauf nämlich sehr gespannt, könnte eine interessante Verbesserung zu meinem GLJPanel werden. 

Gruß,
Fancy


----------



## lumo (16. Sep 2010)

werd mir das programm baldigst anschauen 
danke schon mal!

wenn man nur lwjgl verwendet zum erstellen des fensters, dann sollte der unterschied zwischen c und java nicht all zu groß sein...


----------



## Marco13 (17. Sep 2010)

lumo hat gesagt.:


> wenn man nur lwjgl verwendet zum erstellen des fensters, dann sollte der unterschied zwischen c und java nicht all zu groß sein...



Naja, es stimmt schon: Mehr als die "render()"-Methode wird bei C dann nicht gleich bleiben. Dort gibt es auch keine BufferedImages 

@Fancy: Hab' das Thema mal hier fortgeführt und den Code da gepostet: http://www.java-forum.org/codeschnipsel-u-projekte/105991-directbufferedimage.html#post676751


----------



## Empire Phoenix (17. Sep 2010)

Am rande,w enn es mit Java fertig ist, warum willst du das dann zu C porten? masochist? (geschwindigketistechnis wird es bei 2d eh wayne sein, da is beides mehr als ausreichend)


----------



## lumo (17. Sep 2010)

ich wollte auch nicht mit bufferedimage arbeiten.
z.Zeit lade ich mein png in eine selbst geschriebene image klasse.
im prinzip eine RAW klasse (mit getter/setter)


```
RawImage {
int width
int height
Color[]
}

Color{
byte alpha
byte r
byte g
byte b
Color(int color)
}
```

mit der klasse arbeite ich dann... (ich dachte eigentlich dass es in ogl sicher einen speicher gibt in dem man direkt zeichnen kann... konnte den allerdings noch nicht finden... FBO?!)


----------



## Evil-Devil (17. Sep 2010)

lumo hat gesagt.:


> ganz einfach,
> wenn ichs dann in c umsetzen will muss ich mir nicht wieder nen kopf machen, wie ich 2d/3d-graphiken implementiere
> 
> opengl ist auch plattformunabhängig... (die anwendung muss halt neu compiliert werden)
> läuft aber dann auch auf smartphones OHNE java (iPhone)



Seit wann unterstützt zb. das iPhone normales C? Zwar gibt es für das iPhone OpenGL, aber programmiert wird in Objective C und das differenziert sich abgesehen von Pointern doch sehr von C.


----------



## lumo (17. Sep 2010)

offtopic: die unterschiede von objective c und c/cpp sind nicht so groß (zumindest hätte ich nichts gefunden, was darauf hinweist; dass null nil heisst finde ich jetzt nichts grundlegendes)
also ich gehe davon aus, dass wenn ich ein programm in c schreiben kann, dann auch programme in objective c schreiben kann; wenn ich java 1.1 kann kann ich auch java 1.5 (man muss nur die doku lesen, wenn man nicht weiter kommt)

@thema
das schreiben in eine (OGL) textur könnte man doch per render2texture machen und dann nur einen punkt rendern? (die frage ist ob lesen auch geht, oder ob ich dazu einen speicherklon brauche...)
hätte den vorteil, dass man keine daten kopieren muss


----------



## Guest2 (17. Sep 2010)

lumo hat gesagt.:


> offtopic: die unterschiede von objective c und c/cpp sind nicht so groß (zumindest hätte ich nichts gefunden, was darauf hinweist; dass null nil heisst finde ich jetzt nichts grundlegendes)
> also ich gehe davon aus, dass wenn ich ein programm in c schreiben kann, dann auch programme in objective c schreiben kann; wenn ich java 1.1 kann kann ich auch java 1.5 (man muss nur die doku lesen, wenn man nicht weiter kommt)



Ich befürchte Du unterschätzt die Unterschiede der verschiedenen Programmiersprachen etwas. Klar, die Syntax ist bei allen relativ ähnlich, jedoch ist die Syntax auch der Teil einer Sprache, welchen man normalerweise innerhalb weniger Stunden verinnerlicht hat. Eine Sprache zu können, heißt im wesentlichen aber die Eigenschaften, Strukturen und API einer Sprache effektiv nutzen zu können. Während der Java Entwickler mindestens die Java API nutzt, nutzt der C/C++ Entwickler mindestens STL und BOOST, der Objectiv C Entwickler sein NS* Zeugs.

Zum Beispiel gibt es in C/C++ derzeit mindestens ein halbes Dutzend verschiedener smart pointer. Ich würde mir nicht zutrauen zu wissen welcher derzeit, wann eingesetzt werden sollte. Und das, obwohl ich eigentlich C/C++ mal ganz gut konnte.

Deshalb ihmo nein, nur weil man eine ähnliche Sprache kennt, kann man noch lange keine komplexe Anwendung in der anderen Sprache realisieren. Klar der Einstig ist leichter, aber trotzdem sind imho erstmal kleine Brötchen backen angesagt.


Ähnlich ist das auch mit OpenGL selber. Du nutzt auf dem Desktop normalerweise OpenGL auf dem iPhone aber OpenGL ES (oder gar ES2 ab iPhone 3GS). Es kann Dir daher leicht passieren, dass Du eine Lösung baust, die auf einem der Plattformen nicht laufen wird. 




lumo hat gesagt.:


> @thema
> das schreiben in eine (OGL) textur könnte man doch per render2texture machen und dann nur einen punkt rendern? (die frage ist ob lesen auch geht, oder ob ich dazu einen speicherklon brauche...)
> hätte den vorteil, dass man keine daten kopieren muss



PBO wäre z.B. ein Stichwort. Aber das geht imho nicht auf dem iPhone. Das im Beispiel von Marco verwendete glDrawPixels übrigens imho auch nicht. 

Einzelne Punkte auf der CPU manipulieren zu wollen, wäre sowieso nicht die optimale Lösung. Wenn Du deine Grafiken erst auf der Grafikkarte erzeugst, wird das nicht nur deutlich schneller und würde dem entsprechen, wozu man OpenGL normalerweise nutzt, sondern es würde auch den Anteil des Codes erhöhen, der wirklich portabel wäre.

Gruß,
Fancy (der echte Guest2 )


----------



## lumo (17. Sep 2010)

dann wirds wohl nichts mit coolen animationen 
(wollte u.a. einen wasser-effekt einbauen, den ich bis jetzt in swing und swt implementiert habe...) (software-'rendering' innerhalb eines arrays, und anschließendes umrechnen in swing/swt image klassen mit anschließendem anzeigen)

bleibt nur noch die spielelogik selbst, die meines erachtens fast schon so trivial ist  dass es wohl meine 2 jährige tochter flott lösen kann 

ich wüsste nicht, wie ich das ohne opengl umsetzen kann (fürs iphone)


----------



## Guest2 (17. Sep 2010)

Nuja, Du kannst das ja schon mit OpenGL machen, nur must Du eben damit rechnen, dass Du Dein Spiel schlimmstenfalls 3-mal komplett neu entwickeln musst. Als Fingerübung kann das ja auch sogar recht förderlich sein. 

Auch Deinen Wasser Effekt kann man bestimmt nach OpenGL portieren. Evtl. sogar komplett im Shader, bei OpenGL ES2 muss ja eh alles im Shader gemacht werden. Ich weis aber nicht ob das iPhone 3GS nun nur ES2 oder ob es ES2 und ES1 kann.

Shader hat aber eben den Nachteil, dass man sich da erstmal was einarbeiten muss. So einfach auf nem Array rumreiten st dann nämlich nicht. Imho lohnt es sich aber trotzdem! 

Gruß,
Fancy


----------

