Browse Source

font, font renderer, matrix stack, various improvements, cleanup

Kajetan Johannes Hammerle 5 years ago
parent
commit
386d7e284e

BIN
font.png


BIN
font.xcf


+ 7 - 3
shaders/fragment.fs

@@ -6,8 +6,8 @@ layout (location = 2) in vec4 vertexColor;
 
 layout (binding = 0) uniform sampler2D samp;
 
-uniform mat4 matrix;
-uniform vec2 camera;
+uniform mat4 viewMatrix;
+uniform mat4 modelMatrix;
 uniform float depth;
 uniform vec3 ambientLight;
 
@@ -21,8 +21,8 @@ struct Light
 uniform Light lights[32];
 
 uniform bool useTexture;
+uniform bool useColor;
 uniform bool useLight;
-uniform bool useCameraOffset;
 
 in vec2 tc;
 in vec2 loc;
@@ -48,6 +48,10 @@ void main(void)
         {
             discard;
         }
+        if(useColor)
+        {
+            color = vColor;
+        }
     }
     else
     {

+ 4 - 11
shaders/vertex.vs

@@ -6,8 +6,8 @@ layout (location = 2) in vec4 vertexColor;
 
 layout (binding = 0) uniform sampler2D samp;
 
-uniform mat4 matrix;
-uniform vec2 camera;
+uniform mat4 viewMatrix;
+uniform mat4 modelMatrix;
 uniform float depth;
 uniform vec3 ambientLight;
 
@@ -21,8 +21,8 @@ struct Light
 uniform Light lights[32];
 
 uniform bool useTexture;
+uniform bool useColor;
 uniform bool useLight;
-uniform bool useCameraOffset;
 
 out vec2 tc;
 out vec2 loc;
@@ -32,14 +32,7 @@ void main(void)
 { 
     loc = pos;
 
-    if(useCameraOffset)
-    {
-        gl_Position = matrix * vec4(pos - camera, depth, 1.0);
-    }
-    else
-    {
-        gl_Position = matrix * vec4(pos, depth, 1.0);
-    }
+    gl_Position = viewMatrix * modelMatrix * vec4(pos, depth, 1.0);
 
     tc = tex;
     vColor = vertexColor;

+ 0 - 118
src/me/hammerle/snuviengine/api/Chunk.java

@@ -1,118 +0,0 @@
-package me.hammerle.snuviengine.api;
-
-import java.nio.FloatBuffer;
-import org.lwjgl.BufferUtils;
-import static org.lwjgl.opengl.GL11.*;
-import static org.lwjgl.opengl.GL15.*;
-import static org.lwjgl.opengl.GL20.*;
-import static org.lwjgl.opengl.GL30.*;
-
-public class Chunk
-{
-    private final int vao;
-    private final int vbo;
-    private boolean dirty = true;
-    private final FloatBuffer buffer = BufferUtils.createFloatBuffer(Map.PARTION * Map.PARTION * 24);
-    
-    protected Chunk()
-    {
-        vao = glGenVertexArrays();
-        vbo = glGenBuffers();
-        
-        glBindVertexArray(vao);
-        glBindBuffer(GL_ARRAY_BUFFER, vbo);
-        
-        glEnableVertexAttribArray(0);
-        glVertexAttribPointer(0, 2, GL_FLOAT, false, 16, 0);
-        
-        glEnableVertexAttribArray(1);  
-        glVertexAttribPointer(1, 2, GL_FLOAT, false, 16, 8);
-    }
-    
-    protected void delete()
-    {
-        glDeleteVertexArrays(vao);
-        glDeleteBuffers(vbo);
-    }
-    
-    private void build(short[][] data, int sx, int sy, TextureAtlas atlas)
-    {
-        dirty = false;
-        float f = Engine.TILE_SIZE * Engine.SCALE;
-        float t = 1.0f / 2048.0f;
-        
-        for(int x = sx; x < sx + Map.PARTION; x++)
-        {
-            for(int y = sy; y < sy + Map.PARTION; y++)
-            {
-                if(data[x][y] == -1)
-                {
-                    for(int i = 0; i < 24; i++)
-                    {
-                        buffer.put(-1.0f);
-                    }
-                }
-                else
-                {
-                    float minX = atlas.getTextureMinX(data[x][y], false) + t;
-                    float minY = atlas.getTextureMinY(data[x][y], false) + t;
-                    float maxX = atlas.getTextureMaxX(data[x][y], false) - t;
-                    float maxY = atlas.getTextureMaxY(data[x][y], false) - t;
-
-                    buffer.put(x * f);
-                    buffer.put((y + 1) * f);
-
-                    buffer.put(minX);
-                    buffer.put(maxY);
-
-                    buffer.put(x * f);
-                    buffer.put(y * f);
-
-                    buffer.put(minX);
-                    buffer.put(minY);
-
-                    buffer.put((x + 1) * f);
-                    buffer.put((y + 1) * f);
-
-                    buffer.put(maxX);
-                    buffer.put(maxY);
-
-                    buffer.put((x + 1) * f);
-                    buffer.put((y + 1) * f);
-
-                    buffer.put(maxX);
-                    buffer.put(maxY);
-
-                    buffer.put(x * f);
-                    buffer.put(y * f);
-
-                    buffer.put(minX);
-                    buffer.put(minY);
-
-                    buffer.put((x + 1) * f);
-                    buffer.put(y * f);
-
-                    buffer.put(maxX);
-                    buffer.put(minY);
-                }
-            }
-        }
-        
-        buffer.flip();
-        
-        glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
-    }
-    
-    protected void draw(short[][] data, int sx, int sy, TextureAtlas atlas)
-    {
-        glBindVertexArray(vao);
-        glBindBuffer(GL_ARRAY_BUFFER, vbo);
-        
-        if(dirty)
-        {
-            build(data, sx, sy, atlas);            
-        }
-        
-        glDrawArrays(GL_TRIANGLES, 0, Map.PARTION * Map.PARTION * 6);
-    }
-}

+ 23 - 25
src/me/hammerle/snuviengine/api/ColorRenderer.java

@@ -1,6 +1,7 @@
 package me.hammerle.snuviengine.api;
 
 import java.nio.FloatBuffer;
+import me.hammerle.snuviengine.util.Color;
 import org.lwjgl.BufferUtils;
 import static org.lwjgl.opengl.GL11.*;
 import static org.lwjgl.opengl.GL15.*;
@@ -12,12 +13,9 @@ public class ColorRenderer
     private int vao;
     private int vbo;
     
-    private float r = 0.0f;
-    private float g = 0.0f;
-    private float b = 0.0f;
-    private float a = 0.0f;
+    private float color;
     
-    private FloatBuffer buffer = BufferUtils.createFloatBuffer(18);
+    private FloatBuffer buffer = BufferUtils.createFloatBuffer(9);
     
     private boolean built = false;
     
@@ -32,24 +30,21 @@ public class ColorRenderer
             glBindBuffer(GL_ARRAY_BUFFER, vbo);
 
             glEnableVertexAttribArray(0);
-            glVertexAttribPointer(0, 2, GL_FLOAT, false, 24, 0);
+            glVertexAttribPointer(0, 2, GL_FLOAT, false, 12, 0);
 
             glEnableVertexAttribArray(2);  
-            glVertexAttribPointer(2, 4, GL_FLOAT, false, 24, 8);
+            glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, true, 12, 8);
         });
     }
     
     public void setColor(float r, float g, float b, float a)
     {
-        this.r = r;
-        this.g = g;
-        this.b = b;
-        this.a = a;
+        this.color = Float.intBitsToFloat(Color.get(r * 255.0f, g * 255.0f, b * 255.0f, a * 255.0f));
     }
     
     public void addTriangle(float x1, float y1, float x2, float y2, float x3, float y3)
     {
-        if(buffer.position() + 18 > buffer.capacity())
+        if(buffer.position() + 9 > buffer.capacity())
         {
             FloatBuffer newBuffer = BufferUtils.createFloatBuffer(buffer.capacity() * 2);
             buffer.flip();
@@ -59,24 +54,15 @@ public class ColorRenderer
         
         buffer.put(x1);
         buffer.put(y1);        
-        buffer.put(r);
-        buffer.put(g);
-        buffer.put(b);
-        buffer.put(a);
+        buffer.put(color);
         
         buffer.put(x2);
         buffer.put(y2);        
-        buffer.put(r);
-        buffer.put(g);
-        buffer.put(b);
-        buffer.put(a);
+        buffer.put(color);
         
         buffer.put(x3);
         buffer.put(y3);        
-        buffer.put(r);
-        buffer.put(g);
-        buffer.put(b);
-        buffer.put(a);
+        buffer.put(color);
     }
     
     public void addRectangle(float minX, float minY, float maxX, float maxY)
@@ -95,6 +81,8 @@ public class ColorRenderer
         glBindVertexArray(vao);
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
+        
+        buffer.limit(buffer.capacity());
         built = true;
     }
     
@@ -106,6 +94,16 @@ public class ColorRenderer
         }
         glBindVertexArray(vao);
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
-        glDrawArrays(GL_TRIANGLES, 0, buffer.limit() / 6);
+        glDrawArrays(GL_TRIANGLES, 0, buffer.limit() / 3);
+    }
+    
+    public void delete()
+    {
+        buffer = null;
+        glDeleteVertexArrays(vao);
+        glDeleteBuffers(vbo);
+        vao = -1;
+        vbo = -1;
+        built = false;
     }
 }

+ 198 - 0
src/me/hammerle/snuviengine/api/FontRenderer.java

@@ -0,0 +1,198 @@
+package me.hammerle.snuviengine.api;
+
+import java.nio.FloatBuffer;
+import me.hammerle.snuviengine.util.Color;
+import org.lwjgl.BufferUtils;
+import static org.lwjgl.opengl.GL11.*;
+import static org.lwjgl.opengl.GL15.*;
+import static org.lwjgl.opengl.GL20.*;
+import static org.lwjgl.opengl.GL30.*;
+
+public class FontRenderer
+{
+    private static final int MAX_LENGTH = 256;
+    private static final float[] COLORS = new float[128];
+    private static final float[] DARK_COLORS = new float[128];
+    
+    static
+    {
+        COLORS['0'] = Float.intBitsToFloat(Color.get(0, 0, 0));
+        COLORS['1'] = Float.intBitsToFloat(Color.get(0, 0, 170));
+        COLORS['2'] = Float.intBitsToFloat(Color.get(0, 170, 0));
+        COLORS['3'] = Float.intBitsToFloat(Color.get(0, 170, 170));
+        COLORS['4'] = Float.intBitsToFloat(Color.get(170, 0, 0));
+        COLORS['5'] = Float.intBitsToFloat(Color.get(170, 0, 170));
+        COLORS['6'] = Float.intBitsToFloat(Color.get(255, 170, 0));
+        COLORS['7'] = Float.intBitsToFloat(Color.get(170, 170, 170));
+        COLORS['8'] = Float.intBitsToFloat(Color.get(85, 85, 85));
+        COLORS['9'] = Float.intBitsToFloat(Color.get(85, 85, 255));
+        COLORS['a'] = Float.intBitsToFloat(Color.get(85, 255, 85));
+        COLORS['b'] = Float.intBitsToFloat(Color.get(85, 255, 255));
+        COLORS['c'] = Float.intBitsToFloat(Color.get(255, 85, 85));
+        COLORS['d'] = Float.intBitsToFloat(Color.get(255, 85, 255));
+        COLORS['e'] = Float.intBitsToFloat(Color.get(255, 255, 85));
+        COLORS['f'] = Float.intBitsToFloat(Color.get(255, 255, 255));
+        
+        float factor = 0.5f;
+        DARK_COLORS['0'] = Float.intBitsToFloat(Color.darken(Color.get(0, 0, 0), factor));
+        DARK_COLORS['1'] = Float.intBitsToFloat(Color.darken(Color.get(0, 0, 170), factor));
+        DARK_COLORS['2'] = Float.intBitsToFloat(Color.darken(Color.get(0, 170, 0), factor));
+        DARK_COLORS['3'] = Float.intBitsToFloat(Color.darken(Color.get(0, 170, 170), factor));
+        DARK_COLORS['4'] = Float.intBitsToFloat(Color.darken(Color.get(170, 0, 0), factor));
+        DARK_COLORS['5'] = Float.intBitsToFloat(Color.darken(Color.get(170, 0, 170), factor));
+        DARK_COLORS['6'] = Float.intBitsToFloat(Color.darken(Color.get(255, 170, 0), factor));
+        DARK_COLORS['7'] = Float.intBitsToFloat(Color.darken(Color.get(170, 170, 170), factor));
+        DARK_COLORS['8'] = Float.intBitsToFloat(Color.darken(Color.get(85, 85, 85), factor));
+        DARK_COLORS['9'] = Float.intBitsToFloat(Color.darken(Color.get(85, 85, 255), factor));
+        DARK_COLORS['a'] = Float.intBitsToFloat(Color.darken(Color.get(85, 255, 85), factor));
+        DARK_COLORS['b'] = Float.intBitsToFloat(Color.darken(Color.get(85, 255, 255), factor));
+        DARK_COLORS['c'] = Float.intBitsToFloat(Color.darken(Color.get(255, 85, 85), factor));
+        DARK_COLORS['d'] = Float.intBitsToFloat(Color.darken(Color.get(255, 85, 255), factor));
+        DARK_COLORS['e'] = Float.intBitsToFloat(Color.darken(Color.get(255, 255, 85), factor));
+        DARK_COLORS['f'] = Float.intBitsToFloat(Color.darken(Color.get(255, 255, 255), factor));
+    }
+    
+    private int vao;
+    private int vbo;
+    
+    private float color;
+    
+    // number of floats per rectangle * layers (normal, shadow) * MAX_LENGTH
+    private FloatBuffer buffer = BufferUtils.createFloatBuffer(30 * 2 * MAX_LENGTH);
+    
+    public FontRenderer()
+    {
+        Shader.addTask(() -> 
+        {
+            vao = glGenVertexArrays();
+            vbo = glGenBuffers();
+
+            glBindVertexArray(vao);
+            glBindBuffer(GL_ARRAY_BUFFER, vbo);
+
+            glEnableVertexAttribArray(0);
+            glVertexAttribPointer(0, 2, GL_FLOAT, false, 20, 0);
+
+            glEnableVertexAttribArray(1);  
+            glVertexAttribPointer(1, 2, GL_FLOAT, false, 20, 8);
+            
+            glEnableVertexAttribArray(2);  
+            glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, true, 20, 16);
+            
+            glBufferData(GL_ARRAY_BUFFER, buffer, GL_STREAM_DRAW);
+        });
+    }
+
+    private void addRectangle(float minX, float minY, float maxX, float maxY, float tMinX, float tMinY, float tMaxX, float tMaxY)
+    {
+        buffer.put(minX);
+        buffer.put(maxY);        
+        buffer.put(tMinX);
+        buffer.put(tMaxY);
+        buffer.put(color);
+        
+        buffer.put(minX);
+        buffer.put(minY);        
+        buffer.put(tMinX);
+        buffer.put(tMinY);
+        buffer.put(color);
+        
+        buffer.put(maxX);
+        buffer.put(maxY);        
+        buffer.put(tMaxX);
+        buffer.put(tMaxY);
+        buffer.put(color);
+        
+        buffer.put(maxX);
+        buffer.put(maxY);        
+        buffer.put(tMaxX);
+        buffer.put(tMaxY);
+        buffer.put(color);
+        
+        buffer.put(minX);
+        buffer.put(minY);        
+        buffer.put(tMinX);
+        buffer.put(tMinY);
+        buffer.put(color);
+        
+        buffer.put(maxX);
+        buffer.put(minY);        
+        buffer.put(tMaxX);
+        buffer.put(tMinY);
+        buffer.put(color);
+    }
+    
+    public void drawString(float x, float y, boolean shadow, String s)
+    {
+        int l = Math.min(s.length(), MAX_LENGTH);
+        
+        if(shadow)
+        {
+            color = DARK_COLORS['f'];
+            float oldX = x;
+            float oldY = y;
+            
+            for(int pos = 0; pos < l; pos++)
+            {
+                char c = s.charAt(pos);
+                if(c == '&')
+                {
+                    pos++;
+                    int index = s.charAt(pos);
+                    if(index >= 0 && index <= COLORS.length)
+                    {
+                        color = DARK_COLORS[s.charAt(pos)];
+                    }
+                    continue;
+                }
+
+                float tMinX = (c & 0xF) / 16.0f;
+                float tMinY = 0.9375f - ((c >> 4) / 16.0f);
+                addRectangle(x + 1, y - 1, x + 17, y + 15, tMinX, tMinY, tMinX + 0.0625f, tMinY + 0.0625f);
+                x += 16;
+            }
+            
+            x = oldX;
+            y = oldY;
+        }
+        
+        color = COLORS['f'];
+        for(int pos = 0; pos < l; pos++)
+        {
+            char c = s.charAt(pos);
+            if(c == '&')
+            {
+                pos++;
+                int index = s.charAt(pos);
+                if(index >= 0 && index <= COLORS.length)
+                {
+                    color = COLORS[s.charAt(pos)];
+                }
+                continue;
+            }
+            
+            float tMinX = (c & 0xF) / 16.0f;
+            float tMinY = 0.9375f - ((c >> 4) / 16.0f);
+            addRectangle(x, y, x + 16, y + 16, tMinX, tMinY, tMinX + 0.0625f, tMinY + 0.0625f);
+            x += 16;
+        }
+        
+        buffer.flip();
+        
+        glBindVertexArray(vao);
+        glBindBuffer(GL_ARRAY_BUFFER, vbo);
+        glBufferSubData(GL_ARRAY_BUFFER, 0, buffer);
+        glDrawArrays(GL_TRIANGLES, 0, buffer.limit() / 5);    
+        
+        buffer.limit(buffer.capacity());
+    }
+    
+    public void delete()
+    {
+        buffer = null;
+        glDeleteVertexArrays(vao);
+        glDeleteBuffers(vbo);
+        vao = -1;
+        vbo = -1;
+    }
+}

+ 4 - 73
src/me/hammerle/snuviengine/api/Map.java

@@ -1,14 +1,12 @@
 package me.hammerle.snuviengine.api;
 
+import me.hammerle.snuviengine.game.Chunk;
 import java.util.Random;
-import static org.lwjgl.opengl.GL20.*;
 
 public class Map 
 {
     protected final static int PARTION = 16;
     
-    private final TextureAtlas textures = new TextureAtlas(Engine.TILE_SIZE, Engine.TILE_SIZE, 16, 16);
-    
     private int layers;
     private int width;
     private int height;
@@ -18,48 +16,13 @@ public class Map
     private int pHeight;
     private Chunk[][][] chunks = null;
     
-    private float cameraX;
-    private float cameraY;
-    private boolean dirtyCamera = true;
-    
-    protected Map()
-    {
-    }
-    
-    protected void preInit()
-    {
-    }
-    
-    protected void postInit()
-    {
-        textures.generateTexture();
-    }
-    
-    protected void bind(int program)
+    public Map()
     {
-        
-        dirtyCamera = true;
-        tick(program);
-    }
-    
-    protected void tick(int program)
-    {
-        
-        if(dirtyCamera)
-        {
-            dirtyCamera = false;
-            glUniform2f(glGetUniformLocation(program, "camera"), cameraX, cameraY);
-        }
-    }
-    
-    public TextureAtlas getTextureAtlas()
-    {
-        return textures;
     }
     
     public void load(String path)
     {
-        layers = 2;
+        /*layers = 2;
         width = 64;
         height = 64;
         tiles = new short[layers][width][height];
@@ -106,39 +69,7 @@ public class Map
                     chunks[l][x][y] = new Chunk();
                 }
             }
-        }
-    }
-    
-    protected void draw()
-    {
-        textures.bindTexture();
-        for(int l = 0; l < layers; l++)
-        {
-            for(int x = 0; x < pWidth; x++)
-            {
-                for(int y = 0; y < pHeight; y++)
-                {
-                    chunks[l][x][y].draw(tiles[l], x * PARTION, y * PARTION, textures);
-                }
-            }
-        }
-    }
-    
-    public void setCamera(float x, float y)
-    {
-        cameraX = getViewX(x);
-        cameraY = getViewY(y);
-        dirtyCamera = true;
-    }
-    
-    public float getCameraX()
-    {
-        return cameraX;
-    }
-    
-    public float getCameraY()
-    {
-        return cameraY;
+        }*/
     }
     
     private float getViewX(float x) 

+ 89 - 0
src/me/hammerle/snuviengine/api/MatrixStack.java

@@ -0,0 +1,89 @@
+package me.hammerle.snuviengine.api;
+
+public class MatrixStack
+{
+    private final int capacity;
+    private final float[][] stack;
+    private int index = 0;
+    
+    protected MatrixStack(int capacity)
+    {
+        this.capacity = capacity;
+        stack = new float[capacity][16];
+        
+        stack[index][0] = 1.0f;
+        stack[index][5] = 1.0f;
+        stack[index][10] = 1.0f;
+        stack[index][15] = 1.0f;
+    }
+    
+    protected float[] getData()
+    {
+        return stack[index];
+    }
+    
+    protected void push()
+    {
+        index++;
+        if(index >= capacity)
+        {
+            throw new ShaderException("matrix stack overflow, max capacity is " + capacity);
+        }
+        System.arraycopy(stack[index - 1], 0, stack[index], 0, 16);
+    }
+    
+    protected void pop()
+    {
+        if(index <= 0)
+        {
+            throw new ShaderException("matrix stack underflow");
+        }
+        index--;
+    }
+    
+    protected void scale(float sx, float sy) 
+    {
+        float[] data = stack[index];
+        data[0] *= sx;
+        data[1] *= sx;
+        data[4] *= sy;
+        data[5] *= sy;
+    }
+    
+    protected void translate(float tx, float ty) 
+    {
+        float[] data = stack[index];
+        data[12] += data[0] * tx + data[4] * ty;
+        data[13] += data[1] * tx + data[5] * ty;
+    }
+    
+    protected void translateTo(float tx, float ty) 
+    {
+        float[] data = stack[index];
+        data[0] = 1.0f;
+        data[1] = 0.0f;
+        data[4] = 0.0f;
+        data[5] = 1.0f; 
+        data[12] = tx;
+        data[13] = ty;
+    }
+    
+    protected void rotate(float angle) 
+    {
+        float[] data = stack[index];
+        
+        angle = (float) Math.toRadians(angle);
+        float cos = (float) Math.cos(angle);
+        float sin = (float) Math.sin(angle);
+        
+        float a1 = data[0];
+        float a2 = data[4];
+        data[0] = a1 * cos - a2 * sin;
+        data[4] = a1 * sin + a2 * cos;
+        
+        a1 = data[1];
+        a2 = data[5];
+        data[1] = a1 * cos - a2 * sin;
+        data[5] = a1 * sin + a2 * cos;
+    }
+}

+ 81 - 26
src/me/hammerle/snuviengine/api/Shader.java

@@ -13,37 +13,62 @@ import static org.lwjgl.opengl.GL20.*;
 public final class Shader
 {
     private static int program = -1;
-    private static String[][] lightStrings;
     
     private static final List<Runnable> TASKS = new LinkedList<>();
     
     protected static boolean initDone = false;
     
+    // uniform stuff
+    private static int unifViewMatrix = -1;
+    private static int unifModelMatrix = -1;
+    private static MatrixStack modelMatrix;
+    
+    private static int unifDepth = -1;
+    
+    private static int unifAmbientLight = -1;
+    private static int[][] unifLight;
+    
+    private static int unifUseTexture = -1;
+    private static int unifUseColor = -1;
+    private static int unifUseLight = -1;
+    
     protected static void init()
     {
         program = createShaderProgram("shaders/vertex.vs", "shaders/fragment.fs");
         glUseProgram(program);
         
-        sendMatrix();
-        setCamera(0.0f, 0.0f);
+        unifViewMatrix = glGetUniformLocation(program, "viewMatrix");
+        updateViewMatrix();
+        
+        unifModelMatrix = glGetUniformLocation(program, "modelMatrix");
+        modelMatrix = new MatrixStack(20);
+        updateMatrix();
+        
+        unifDepth = glGetUniformLocation(program, "depth");
         setDepth(0.0f);
+        
+        unifAmbientLight = glGetUniformLocation(program, "ambientLight");
         setAmbientLight(1.0f, 1.0f, 1.0f);
         
-        lightStrings = new String[32][3];
-        for(int index = 0; index < lightStrings.length; index++)
+        unifLight = new int[32][3];
+        for(int index = 0; index < unifLight.length; index++)
         {
-            lightStrings[index][0] = "lights[" + index + "].color";
-            lightStrings[index][1] = "lights[" + index + "].pos";
-            lightStrings[index][2] = "lights[" + index + "].strength";
-            
+            unifLight[index][0] = glGetUniformLocation(program, "lights[" + index + "].color");
+            unifLight[index][1] = glGetUniformLocation(program, "lights[" + index + "].pos");
+            unifLight[index][2] = glGetUniformLocation(program, "lights[" + index + "].strength");
             setLightColor(index, 0.0f, 0.0f, 0.0f);
             setLightLocation(index, 0.0f, 0.0f);
             setLightStrength(index, 0.0f);
         }
         
+        unifUseTexture = glGetUniformLocation(program, "useTexture");
         setTextureUsing(false);
+        
+        unifUseColor = glGetUniformLocation(program, "useColor");
+        setColorUsing(false);
+        
+        unifUseLight = glGetUniformLocation(program, "useLight");
         setLightUsing(false);
-        setCameraUsing(false);
         
         initDone = true;
     }
@@ -62,7 +87,7 @@ public final class Shader
         }
     }
     
-    private static void sendMatrix()
+    private static void updateViewMatrix()
     {
         FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
         
@@ -88,27 +113,57 @@ public final class Shader
         
         buffer.flip();
         
-        glUniformMatrix4fv(glGetUniformLocation(program, "matrix"), false, buffer);
+        glUniformMatrix4fv(unifViewMatrix, false, buffer);
+    }
+    
+    public static void updateMatrix()
+    {
+        glUniformMatrix4fv(unifModelMatrix, false, modelMatrix.getData());
+    }
+    
+    public static void pushMatrix()
+    {
+        modelMatrix.push();
     }
     
-    public static void setCamera(float x, float y)
+    public static void popMatrix()
     {
-        glUniform2f(glGetUniformLocation(program, "camera"), x, y);
+        modelMatrix.pop();
+    }
+    
+    public static void translate(float tx, float ty)
+    {
+        modelMatrix.translate(tx, ty);
+    }
+    
+    public static void translateTo(float tx, float ty)
+    {
+        modelMatrix.translateTo(tx, ty);
+    }
+    
+    public static void scale(float sx, float sy)
+    {
+        modelMatrix.scale(sx, sy);
+    }
+    
+    public static void rotate(float angle)
+    {
+        modelMatrix.rotate(angle);
     }
     
     public static void setDepth(float depth)
     {
-        glUniform1f(glGetUniformLocation(program, "depth"), depth);
+        glUniform1f(unifDepth, depth);
     }
     
     public static void setAmbientLight(float r, float g, float b)
     {
-        glUniform3f(glGetUniformLocation(program, "ambientLight"), r, g, b);
+        glUniform3f(unifAmbientLight, r, g, b);
     }
     
     private static void checkLightIndex(int index)
     {
-        if(index < 0 || index > lightStrings.length)
+        if(index < 0 || index > unifLight.length)
         {
             throw new ShaderException("'" + index + "' is not a valid light index");
         }
@@ -117,34 +172,34 @@ public final class Shader
     public static void setLightColor(int index, float r, float g, float b)
     {
         checkLightIndex(index);
-        glUniform3f(glGetUniformLocation(program, lightStrings[index][0]), r, g, b);
+        glUniform3f(unifLight[index][0], r, g, b);
     }
     
     public static void setLightLocation(int index, float x, float y)
     {
         checkLightIndex(index);
-        glUniform2f(glGetUniformLocation(program, lightStrings[index][1]), x, y);
+        glUniform2f(unifLight[index][1], x, y);
     }
     
     public static void setLightStrength(int index, float strength)
     {
         checkLightIndex(index);
-        glUniform1f(glGetUniformLocation(program, lightStrings[index][2]), strength);
+        glUniform1f(unifLight[index][2], strength);
     }
     
     public static void setTextureUsing(boolean use)
     {
-        glUniform1i(glGetUniformLocation(program, "useTexture"), use ? 1 : 0);
+        glUniform1i(unifUseTexture, use ? 1 : 0);
     }
     
-    public static void setLightUsing(boolean use)
+    public static void setColorUsing(boolean use)
     {
-        glUniform1i(glGetUniformLocation(program, "useLight"), use ? 1 : 0);
+        glUniform1i(unifUseColor, use ? 1 : 0);
     }
     
-    public static void setCameraUsing(boolean use)
+    public static void setLightUsing(boolean use)
     {
-        glUniform1i(glGetUniformLocation(program, "useCameraOffset"), use ? 1 : 0);
+        glUniform1i(unifUseLight, use ? 1 : 0);
     }
     
     // -------------------------------------------------------------------------
@@ -245,7 +300,7 @@ public final class Shader
         compiled = glGetProgrami(vfprogram, GL_LINK_STATUS);
         if(compiled != 1)
         {
-            throw new ShaderException("failed linking shaders '" + vertex + "' and '" + fragment + "' " + compiled);
+            throw new ShaderException("failed linking shaders '" + vertex + "' and '" + fragment + "' " + compiled + " " + glGetProgramInfoLog(vfprogram));
         }
 
         glDeleteShader(vShader);

+ 13 - 1
src/me/hammerle/snuviengine/api/TextureRenderer.java

@@ -36,7 +36,7 @@ public class TextureRenderer
     
     public void addTriangle(float x1, float y1, float x2, float y2, float x3, float y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3)
     {
-        if(buffer.position() + 18 > buffer.capacity())
+        if(buffer.position() + 12 > buffer.capacity())
         {
             FloatBuffer newBuffer = BufferUtils.createFloatBuffer(buffer.capacity() * 2);
             buffer.flip();
@@ -76,6 +76,8 @@ public class TextureRenderer
         glBindVertexArray(vao);
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
+        
+        buffer.limit(buffer.capacity());
         built = true;
     }
     
@@ -89,4 +91,14 @@ public class TextureRenderer
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         glDrawArrays(GL_TRIANGLES, 0, buffer.limit() / 4);
     }
+    
+    public void delete()
+    {
+        buffer = null;
+        glDeleteVertexArrays(vao);
+        glDeleteBuffers(vbo);
+        vao = -1;
+        vbo = -1;
+        built = false;
+    }
 }

+ 8 - 0
src/me/hammerle/snuviengine/game/Chunk.java

@@ -0,0 +1,8 @@
+package me.hammerle.snuviengine.game;
+
+public class Chunk
+{
+    public Chunk()
+    {
+    }
+}

+ 67 - 5
src/me/hammerle/snuviengine/game/Game.java

@@ -2,11 +2,14 @@ package me.hammerle.snuviengine.game;
 
 import me.hammerle.snuviengine.api.ColorRenderer;
 import me.hammerle.snuviengine.api.Engine;
+import me.hammerle.snuviengine.api.FontRenderer;
+import me.hammerle.snuviengine.api.FontRenderer;
 import me.hammerle.snuviengine.api.KeyBinding;
 import me.hammerle.snuviengine.api.KeyHandler;
 import me.hammerle.snuviengine.api.Shader;
 import me.hammerle.snuviengine.api.Texture;
 import me.hammerle.snuviengine.api.TextureRenderer;
+import me.hammerle.snuviengine.util.Clock;
 import static org.lwjgl.glfw.GLFW.*;
 
 public class Game extends Engine
@@ -20,6 +23,9 @@ public class Game extends Engine
     private final TextureRenderer tr = new TextureRenderer();
     private final Texture t = new Texture("images/out3.png");
     
+    private final FontRenderer fr = new FontRenderer();
+    private final Texture text = new Texture("font.png");
+    
     float x = 0.0f;
     float y = 0.0f;
     
@@ -27,7 +33,7 @@ public class Game extends Engine
     
     public Game()
     {
-        t.addAnimation(0, 0, "water1.png", "water2.png", "water3.png", "water2.png");
+        t.addAnimation(0, 0, "images/water1.png", "images/water2.png", "images/water3.png", "images/water2.png");
     }
     
     @Override
@@ -82,26 +88,82 @@ public class Game extends Engine
             counter = 0;
             t.nextFrame();
         }
+        
+        x += 1f;
     }
     
+    private static final Clock clock = new Clock(1000);
+    
     @Override
     public void renderTick()
     {
         //Shader.drawMap();
         
-        Shader.setTextureUsing(false);
-        cr.setColor(1.0f, 1.0f, 0.f, 1.0f);
-        cr.addRectangle(20, 20, 300, 300);
+        /*Shader.setTextureUsing(false);
+
+        Shader.translateTo(500, 250);
+        Shader.scale(5, 5);
+        Shader.rotate(x);
+        Shader.translate(-10, -10);
+        Shader.updateMatrix();
+        
+        cr.setColor(0.75f, 0.75f, 0.75f, 1.0f);
+        cr.addRectangle(0, 0, 20, 20);
         cr.build();
         cr.draw();
         
+        Shader.pushMatrix();
+        Shader.translate(30, 30);
+        Shader.rotate(x);
+        Shader.translate(-5, -5);
+        Shader.updateMatrix();
+        Shader.popMatrix();
+        
+        cr.setColor(0.5f, 0.5f, 0.5f, 1.0f);
+        cr.addRectangle(0, 0, 5, 5);
+        cr.build();
+        cr.draw();
+        
+        Shader.pushMatrix();
+        Shader.translate(30, 10);
+        Shader.rotate(x);
+        Shader.translate(-5, -5);
+        Shader.updateMatrix();
+        Shader.popMatrix();
+        
+        cr.setColor(0.5f, 1.0f, 0.5f, 1.0f);
+        cr.addRectangle(0, 0, 5, 5);
+        cr.build();
+        cr.draw();*/
+        
+        clock.start();
+        Shader.setColorUsing(false);
         Shader.setTextureUsing(true);
         t.bindTexture();
-        for(int i = 0; i < 1000; i += 64)
+        for(int i = 0; i < 192; i += 64)
         {
             tr.addRectangle(i, 64, i + 64, 128, 0.0f, 0.0f, 1.0f, 1.0f);
         }
         tr.build();
         tr.draw();
+        
+        text.bindTexture();
+        Shader.setColorUsing(true);
+        
+        Shader.pushMatrix();
+        Shader.translateTo(0.0f, 0.0f);
+        //Shader.scale(3, 3);
+        Shader.updateMatrix();
+        
+        for(int i = 0; i < 30; i++)
+        {
+            fr.drawString(0.0f, i * 16.0f, true, "&üDas &0i&1s&2t &3e&4i&5n &6F&7a&8r&9b&ae&bn&ct&de&es&ft. Das &0i&1s&2t &3e&4i&5n &6F&7a&8r&9b&ae&bn&ct&de&es&ft.");
+        }
+        
+        Shader.popMatrix();
+        Shader.updateMatrix();
+
+        clock.stop();
+        clock.printTime("Text:");
     }
 }

+ 43 - 0
src/me/hammerle/snuviengine/util/Clock.java

@@ -0,0 +1,43 @@
+package me.hammerle.snuviengine.util;
+
+public class Clock
+{
+    private int dataLength;
+    private long[] data;
+    private int index = 0;
+    private long sum = 0;
+    private long time;
+    private boolean stable = false;
+    
+    public Clock(int dataLength)
+    {
+        this.dataLength = dataLength;
+        data = new long[dataLength];
+    }
+    
+    public void start()
+    {
+        time = System.nanoTime();
+    }
+    
+    public void stop()
+    {
+        time = System.nanoTime() - time;
+        sum -= data[index];
+        sum += time;
+        data[index] = time;
+        index = (index + 1) % dataLength;
+        if(index == 0)
+        {
+            stable = true;
+        }
+    }
+    
+    public void printTime(String m)
+    {
+        if(stable)
+        {
+            System.out.println( m + " " + (sum / dataLength));
+        }
+    }
+}

+ 27 - 0
src/me/hammerle/snuviengine/util/Color.java

@@ -0,0 +1,27 @@
+package me.hammerle.snuviengine.util;
+
+public class Color
+{
+    public static int get(int r, int g, int b, int a)
+    {
+        return (r & 0xFF) | ((g & 0xFF) << 8) | ((b & 0xFF) << 16) | ((a & 0xFF) << 24);
+    }
+    
+    public static int get(float r, float g, float b, float a)
+    {
+        return get((int) r, (int) g, (int) b, (int) a);
+    }
+    
+    public static int darken(int rgba, float factor)
+    {
+        return ((int) ((rgba & 0xFF) * factor) & 0xFF) | 
+                (((int) (((rgba >> 8) & 0xFF) * factor) & 0xFF) << 8) | 
+                (((int) (((rgba >> 16) & 0xFF) * factor) & 0xFF) << 16) | 
+                (rgba & 0xFF000000);
+    }
+    
+    public static int get(int r, int g, int b)
+    {
+        return get(r, g, b, 255);
+    }
+}