diff --git a/Image.java b/Image.java
index 3be578c..71b33de 100644
--- a/Image.java
+++ b/Image.java
@@ -33,14 +33,29 @@ public class Image
         return points;
     }
     
+    /**
+     * Liest eine JPG-Bilddatei ein und gibt diese als ArrayList von RGB-Objekten zurück
+     * 
+     * @param filename Dateiname die eingelesen werden soll
+     * @return BufferedImage
+     * @throws Exception
+     */
+    public static BufferedImage loadFile(String filename) throws Exception {
+        ArrayList<RGB> points = new ArrayList<>();
+        
+        File file= new File(filename);
+        return ImageIO.read(file);
+    }
+    
     /**
      * Schreibt die RGB-Daten in eine Datei
      * 
      * @param input Dateiname der ursprünglichen Datei (wird für Dimensionen gebraucht)
      * @param output Dateiname der neuen Datei
      * @param data RGB-Daten der einzelnen Pixel
+     * @return BufferedImage
      */
-    public static void writeFile(String input, String output, ArrayList<RGB> data) throws Exception {
+    public static BufferedImage writeFile(String input, String output, ArrayList<RGB> data) throws Exception {
         File file = new File(input);
         BufferedImage img = ImageIO.read(file);
         
@@ -54,8 +69,12 @@ public class Image
             }
         }
         
-        File f = new File(output);
-        ImageIO.write(img, "jpg", f);
+        if (output != "") {
+            File f = new File(output);
+            ImageIO.write(img, "jpg", f);
+        }
+        
+        return img;
     }
     
     /**
@@ -66,8 +85,9 @@ public class Image
      * @param output Dateiname der neuen Datei
      * @param data RGB-Daten der einzelnen Pixel
      * @param quants Quantifizierungs-Punkte
+     * @return BufferedImage
      */
-    public static void writeFile(String input, String target, ArrayList<RGB> data, ArrayList<RGB> quants) throws Exception {
+    public static BufferedImage writeFile(String input, String target, ArrayList<RGB> data, ArrayList<RGB> quants) throws Exception {
         ArrayList<RGB> q = new ArrayList<>();
         
         // Mappe punkte auf quantifizierte Punkte
@@ -76,6 +96,6 @@ public class Image
         }
         
         // schreibe Datei
-        writeFile(input, target, q);
+        return writeFile(input, target, q);
     }
 }
diff --git a/OGL_Window.java b/OGL_Window.java
new file mode 100644
index 0000000..8ea719e
--- /dev/null
+++ b/OGL_Window.java
@@ -0,0 +1,399 @@
+import com.jogamp.opengl.GL2;
+import com.jogamp.opengl.glu.GLU;
+import com.jogamp.opengl.GLAutoDrawable;
+import com.jogamp.opengl.GLCapabilities;
+import com.jogamp.opengl.GLEventListener;
+import com.jogamp.opengl.GLProfile;
+import com.jogamp.opengl.awt.GLCanvas;
+
+import javax.swing.JFrame;
+import java.awt.Color;
+import java.awt.event.KeyListener;
+import java.awt.event.KeyEvent;
+
+import java.util.ArrayList;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.ArrayList;
+import java.io.File;
+import java.util.Collections;
+
+import java.awt.image.BufferedImage;
+
+public class OGL_Window implements GLEventListener, KeyListener, ActionListener {
+    private int imgHeight = 200;
+    
+    private JFrame frame;
+    private JPanel drawPanel;
+    private JPanel drawImg;
+    private JPanel drawQImg;
+    
+    private JButton vl;
+    private JButton vr;
+    private JButton vu;
+    private JButton vd;
+    
+    private JButton b_load;
+    private JButton b_gen;
+    private JButton b_epoc;
+    private JButton b_reset;
+    private JButton b_save;
+
+    private JComboBox s_input;
+    private JTextField t_anz;
+    private JTextField t_output;
+
+    private final GLCanvas glcanvas;
+    
+    private ArrayList<RGB> image;
+    private ArrayList<RGB> orig;
+    private ArrayList<RGB> quants;
+    
+    private BufferedImage img;
+    private BufferedImage qimg;
+    
+    private int azimut = 25;
+    private int rot = 45;
+    
+    @Override
+    public void display(GLAutoDrawable drawable) {
+        final GL2 gl = drawable.getGL().getGL2();
+
+        gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT | GL2.GL_STENCIL_BUFFER_BIT);
+
+        final GLU glu = GLU.createGLU(gl);
+        gl.glMatrixMode(GL2.GL_PROJECTION);
+        gl.glLoadIdentity();
+        double w = this.drawPanel.getWidth();
+        double h = this.drawPanel.getHeight();
+        glu.gluPerspective(45,w/h,0.1,100);
+        gl.glMatrixMode(GL2.GL_MODELVIEW);
+        gl.glLoadIdentity();
+        glu.gluLookAt(
+            0,0,3,
+            0,0,0,
+            0,1,0
+        );
+        gl.glRotatef(this.azimut,1,0,0);
+        gl.glRotatef(-this.rot,0,1,0);
+
+        gl.glLineWidth(5);
+        gl.glBegin(GL2.GL_LINES);
+        
+        gl.glColor4f(0,0,0,1);
+        gl.glVertex3f(0,0,0);
+        gl.glColor4f(1,0,0,1);
+        gl.glVertex3f(1,0,0);
+        
+        gl.glColor4f(0,0,0,1);
+        gl.glVertex3f(0,0,0);
+        gl.glColor4f(0,1,0,1);
+        gl.glVertex3f(0,1,0);
+        
+        gl.glColor4f(0,0,0,1);
+        gl.glVertex3f(0,0,0);
+        gl.glColor4f(0,0,1,1);
+        gl.glVertex3f(0,0,1);
+        gl.glEnd();
+                
+        gl.glEnable(GL2.GL_BLEND);
+        gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
+
+        gl.glPointSize(8);
+        gl.glBegin(GL2.GL_POINTS);
+        for (RGB p : this.image) {
+            gl.glColor4f(((float)(p.r))/256/4,((float)(p.g))/256/4,((float)(p.b))/256/4,0.15f);
+            gl.glVertex3f(
+                ((float)(p.r))/256,
+                ((float)(p.g))/256,
+                ((float)(p.b))/256
+            );
+        }
+        gl.glEnd();
+        
+        gl.glPointSize(20);
+        gl.glBegin(GL2.GL_POINTS);
+        for (RGB p : this.quants) {
+            gl.glColor4f(((float)(p.r))/256,((float)(p.g))/256,((float)(p.b))/256,1f);
+            gl.glVertex3f(
+                ((float)(p.r))/256,
+                ((float)(p.g))/256,
+                ((float)(p.b))/256
+            );
+        }
+        gl.glEnd();
+        
+        gl.glPointSize(20);
+        gl.glBegin(GL2.GL_POINTS);
+        gl.glColor4ub((byte)0,(byte)0,(byte)0,(byte)255);
+        gl.glVertex3f(0,0,0);
+        gl.glEnd();
+    }
+    
+    @Override
+    public void dispose(GLAutoDrawable arg0) {}
+
+    @Override
+    public void init(GLAutoDrawable drawable) {} 
+
+    @Override
+    public void reshape(GLAutoDrawable drawable, int arg1, int arg2, int arg3, int arg4) {}
+    
+    @Override
+    public void keyPressed(KeyEvent e) {}
+    
+    @Override
+    public void keyTyped(KeyEvent e) {}
+    
+    @Override
+    public void keyReleased(KeyEvent e) {
+        if (e.getKeyCode() == KeyEvent.VK_LEFT) {
+            this.rot += 15;
+        } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
+            this.rot -= 15;
+        } else if (e.getKeyCode() == KeyEvent.VK_UP) {
+            this.azimut -= 15;
+        } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
+            this.azimut += 15;
+        } else {
+            return;
+        }
+        
+        this.glcanvas.repaint();
+    }
+    
+    private OGL_Window() {
+        this.image = new ArrayList<>();
+        this.orig = new ArrayList<>();
+        this.quants = new ArrayList<>();
+        
+        //getting the capabilities object of GL2 profile
+        final GLProfile profile = GLProfile.get(GLProfile.GL2);
+        GLCapabilities capabilities = new GLCapabilities(profile);
+        capabilities.setBackgroundOpaque(false);
+
+        // The canvas
+        glcanvas = new GLCanvas(capabilities);
+        glcanvas.addGLEventListener(this);
+        glcanvas.setSize(500, 500);
+        glcanvas.setBackground(new Color(220, 220, 220));
+        glcanvas.addKeyListener(this);
+
+        OGL_Window that = this;
+
+        //creating frame
+        frame = new JFrame("RGB Quantisierer");
+        frame.addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) { System.exit(0); }
+        });
+        frame.addComponentListener(new ComponentAdapter() {
+           public void componentResized(ComponentEvent e) {
+               int width = (int)that.frame.getSize().getWidth();
+               int height = (int)that.frame.getSize().getHeight() - 160 - that.imgHeight;
+               that.glcanvas.setSize(width, height);
+               that.drawPanel.setSize(new Dimension(width, height));
+           }
+        });
+        
+        JPanel mainPanel = new JPanel();
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+        
+        drawPanel = new JPanel();
+        JPanel view = new JPanel();
+        JPanel steps = new JPanel();
+        JPanel config = new JPanel();
+        JPanel images = new JPanel();
+
+        mainPanel.add(drawPanel);
+        mainPanel.add(view);
+        mainPanel.add(steps);
+        mainPanel.add(config);
+        mainPanel.add(images);
+        
+        vl = new JButton("<");
+        vl.addActionListener(this);
+        view.add(vl);
+        vr = new JButton(">");
+        vr.addActionListener(this);
+        view.add(vr);
+        vu = new JButton("^");
+        vu.addActionListener(this);
+        view.add(vu);
+        vd = new JButton("v");
+        vd.addActionListener(this);
+        view.add(vd);
+        
+        b_load = new JButton("Datei laden");
+        b_load.addActionListener(this);
+        steps.add(b_load);
+        
+        b_gen = new JButton("Zufällige Punkte erzeugen");
+        b_gen.addActionListener(this);
+        steps.add(b_gen);
+
+        b_epoc = new JButton("Epoche durchspielen");
+        b_epoc.addActionListener(this);
+        steps.add(b_epoc);
+
+        b_reset = new JButton("Punkte versetzen");
+        b_reset.addActionListener(this);
+        steps.add(b_reset);
+        
+        b_save = new JButton("Datei speichern");
+        b_save.addActionListener(this);
+        steps.add(b_save);
+        
+        config.add(new JLabel("Input:"));
+        s_input = new JComboBox(getJPGs());
+        config.add(s_input);
+
+        config.add(new JLabel("Anzahl Punkte:"));
+        t_anz = new JTextField("32");
+        t_anz.setPreferredSize(new Dimension(100,20));
+        config.add(t_anz);
+
+        config.add(new JLabel("Output:"));
+        t_output = new JTextField("output.jpg");
+        t_output.setPreferredSize(new Dimension(100,20));
+        config.add(t_output);
+        
+        drawImg = new JPanel();
+        drawImg.setPreferredSize(new Dimension(this.imgHeight + 50,this.imgHeight + 10));
+        drawQImg = new JPanel();
+        drawQImg.setPreferredSize(new Dimension(this.imgHeight + 50,this.imgHeight + 10));
+        images.add(drawImg);
+        images.add(drawQImg);
+        
+        frame.add(mainPanel);
+        drawPanel.add(glcanvas);
+
+        frame.pack();
+        frame.setVisible(true);
+    }
+    
+    /**
+     * Button-Reaktivität
+     * 
+     * @param e ActionEvent
+     */
+    public void actionPerformed(ActionEvent e) {
+        /**
+         * Pfeilbuttons: Ändern der Ansicht
+         */
+        if (e.getSource() == this.vr) this.rot = (this.rot + 345) % 360;
+        if (e.getSource() == this.vl) this.rot = (this.rot + 15) % 360;
+        if (e.getSource() == this.vu) this.azimut = (this.azimut + 345) % 360;
+        if (e.getSource() == this.vd) this.azimut = (this.azimut + 15) % 360;
+        
+        /**
+         * Datei laden und RGB-Daten in ArrayList speichern
+         */
+        if (e.getSource() == this.b_load) {
+            try {
+                this.orig = Image.readFile("./inputs/" + (String)this.s_input.getSelectedItem());
+                this.img = Image.loadFile("./inputs/" + (String)this.s_input.getSelectedItem());
+                this.image = new ArrayList<>();
+                for (RGB p : this.orig) {
+                    // kopiere die originalen Daten, damit die Liste später gemischt werden kann
+                    this.image.add(p);
+                }
+                
+                this.drawImage(this.img, this.drawImg);
+            } catch (Exception ex) {}
+        }
+        /**
+         * Zufällige Punkte erzeugen
+         */
+        if (e.getSource() == this.b_gen) {
+            this.quants = new ArrayList<>();
+            for (int i = 0; i < Integer.parseInt(this.t_anz.getText()); i++) {
+                this.quants.add(new RGB(true));
+            }
+
+            try {
+                BufferedImage i = Image.writeFile("./inputs/" + (String)this.s_input.getSelectedItem(), "", this.orig, this.quants);
+                this.drawImage(i, this.drawQImg);
+            } catch (Exception ex) {}
+        }
+        /**
+         * Epoche durchlaufen
+         */
+        if (e.getSource() == this.b_epoc) {
+            Quant.doEpoch(this.image, this.quants);
+
+            try {
+                BufferedImage i = Image.writeFile("./inputs/" + (String)this.s_input.getSelectedItem(), "", this.orig, this.quants);
+                this.drawImage(i, this.drawQImg);
+            } catch (Exception ex) {}
+        }
+        /**
+         * Nicht bewegte Punkte versetzen
+         */
+        if (e.getSource() == this.b_reset) {
+            Quant.resetQuants(this.quants);
+
+            try {
+                BufferedImage i = Image.writeFile("./inputs/" + (String)this.s_input.getSelectedItem(), "", this.orig, this.quants);
+                this.drawImage(i, this.drawQImg);
+            } catch (Exception ex) {}
+        }
+        /**
+         * quantifiziertes Bild speichern
+         */
+        if (e.getSource() == this.b_save) {
+            try {
+                Image.writeFile("./inputs/" + (String)this.s_input.getSelectedItem(), "./outputs/" + this.t_output.getText(), this.orig, this.quants);
+            } catch (Exception ex) {}
+        }
+
+        // neue Anzeige rendern
+        this.glcanvas.repaint();
+    }
+    
+    private void drawImage(BufferedImage i, JPanel p) {
+        int w = i.getWidth();
+        int h = i.getHeight();
+        
+        if (w > h) {
+            h = h * this.imgHeight / w;
+            w = this.imgHeight;
+        } else {
+            w = w * this.imgHeight / h;
+            h = this.imgHeight;
+        }
+        
+        JLabel img = new JLabel(new ImageIcon(i.getScaledInstance(w,h,1)));
+        img.setPreferredSize(new Dimension(this.imgHeight, this.imgHeight));
+        p.removeAll();
+        p.add(img);
+        p.revalidate();
+    }
+    
+    /**
+     * Lies die vorhandenen JPG-Dateien aus dem Ordner inputs aus
+     * 
+     * @return String[] Dateinamen
+     */
+    private String[] getJPGs() {
+        ArrayList<String> result = new ArrayList<String>();
+        
+        File d = new File("./inputs/");
+        File[] list = d.listFiles();
+        for(int i=0; i<list.length; i++) {
+            String n = list[i].getName();
+            // nur JPG-Bilder
+            if (n.matches(".*\\.[jJ][pP][eE]?[gG]$")) {
+                result.add(n);
+            }
+        }
+
+        String[] ret = new String[result.size()];
+        return result.toArray(ret);
+    }
+
+    public static void main() throws Exception {
+        new OGL_Window();
+    }
+}
\ No newline at end of file
diff --git a/README.TXT b/README.TXT
index 2a754b7..bb81d23 100644
--- a/README.TXT
+++ b/README.TXT
@@ -4,16 +4,19 @@ PROJEKTZWECK: Liest ein Bild aus einer JPG-Datei ein und stellt die
     Anschließend werden zufallsverteilte Punkte den Originaldaten
     angenähert um  abschließend das Bild auf diese Farben reduziert
     wieder abzuspeichern.
-VERSION oder DATUM: 1.0.1 (26.10.2023)
-WIE IST DAS PROJEKT ZU STARTEN: Instanz der Klasse Window anlegen
+VERSION oder DATUM: 1.1 (27.10.2023)
+WIE IST DAS PROJEKT ZU STARTEN: OGL_Window -> main()-Methode starten
 AUTOR: Alexander Kimmig (a.kimmig@dhg-rw.de)
 BENUTZERHINWEISE: Die ChartDirector_s.jar muss in den BlueJ-Einstellungen
     als externe Benutzerbibliothek eingebunden werden.
     (Quelle: https://www.advsofteng.com/doc/cdjava.htm)
 
 CHANGELOG:
+* Version 1.1 (27.10.2023)
+    * umgestellt auf OpenGL, manuelles Rendering
+    * 
 * Version 1.0.1 (26.10.2023)
-    *  Möglichkeit, das Fenster in kleinerer Auflösung anzuzeigen
-    *  Möglichkeit, die Punktwolke farbig anzuzeigen
-       -> Achtung: sehr langsam, nur mit kleinem Bild möglich!
+    * Möglichkeit, das Fenster in kleinerer Auflösung anzuzeigen
+    * Möglichkeit, die Punktwolke farbig anzuzeigen
+      -> Achtung: sehr langsam, nur mit kleinem Bild möglich!
 * Version 1.0 (20.10.2023)
\ No newline at end of file
diff --git a/Window.java b/Window.java
index 8655e47..5b1718b 100644
--- a/Window.java
+++ b/Window.java
@@ -1,3 +1,7 @@
+/**
+ * BITTE NICHT MEHR NUTZEN -> stattdessen OGL_Window verwenden!
+ */
+
 import ChartDirector.*;
 import javax.swing.*;
 import java.awt.*;
diff --git a/inputs/gras_gross.jpg b/inputs/gras_gross.jpg
new file mode 100644
index 0000000..721b8ef
Binary files /dev/null and b/inputs/gras_gross.jpg differ
diff --git a/outputs/output4.jpg b/outputs/output4.jpg
new file mode 100644
index 0000000..c29966c
Binary files /dev/null and b/outputs/output4.jpg differ