Bladeren bron

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

Kajetan Johannes Hammerle 6 jaren geleden
bovenliggende
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;
 layout (binding = 0) uniform sampler2D samp;
 
 
-uniform mat4 matrix;
-uniform vec2 camera;
+uniform mat4 viewMatrix;
+uniform mat4 modelMatrix;
 uniform float depth;
 uniform float depth;
 uniform vec3 ambientLight;
 uniform vec3 ambientLight;
 
 
@@ -21,8 +21,8 @@ struct Light
 uniform Light lights[32];
 uniform Light lights[32];
 
 
 uniform bool useTexture;
 uniform bool useTexture;
+uniform bool useColor;
 uniform bool useLight;
 uniform bool useLight;
-uniform bool useCameraOffset;
 
 
 in vec2 tc;
 in vec2 tc;
 in vec2 loc;
 in vec2 loc;
@@ -48,6 +48,10 @@ void main(void)
         {
         {
             discard;
             discard;
         }
         }
+        if(useColor)
+        {
+            color = vColor;
+        }
     }
     }
     else
     else
     {
     {

+ 4 - 11
shaders/vertex.vs

@@ -6,8 +6,8 @@ layout (location = 2) in vec4 vertexColor;
 
 
 layout (binding = 0) uniform sampler2D samp;
 layout (binding = 0) uniform sampler2D samp;
 
 
-uniform mat4 matrix;
-uniform vec2 camera;
+uniform mat4 viewMatrix;
+uniform mat4 modelMatrix;
 uniform float depth;
 uniform float depth;
 uniform vec3 ambientLight;
 uniform vec3 ambientLight;
 
 
@@ -21,8 +21,8 @@ struct Light
 uniform Light lights[32];
 uniform Light lights[32];
 
 
 uniform bool useTexture;
 uniform bool useTexture;
+uniform bool useColor;
 uniform bool useLight;
 uniform bool useLight;
-uniform bool useCameraOffset;
 
 
 out vec2 tc;
 out vec2 tc;
 out vec2 loc;
 out vec2 loc;
@@ -32,14 +32,7 @@ void main(void)
 { 
 { 
     loc = pos;
     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;
     tc = tex;
     vColor = vertexColor;
     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;
 package me.hammerle.snuviengine.api;
 
 
 import java.nio.FloatBuffer;
 import java.nio.FloatBuffer;
+import me.hammerle.snuviengine.util.Color;
 import org.lwjgl.BufferUtils;
 import org.lwjgl.BufferUtils;
 import static org.lwjgl.opengl.GL11.*;
 import static org.lwjgl.opengl.GL11.*;
 import static org.lwjgl.opengl.GL15.*;
 import static org.lwjgl.opengl.GL15.*;
@@ -12,12 +13,9 @@ public class ColorRenderer
     private int vao;
     private int vao;
     private int vbo;
     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;
     private boolean built = false;
     
     
@@ -32,24 +30,21 @@ public class ColorRenderer
             glBindBuffer(GL_ARRAY_BUFFER, vbo);
             glBindBuffer(GL_ARRAY_BUFFER, vbo);
 
 
             glEnableVertexAttribArray(0);
             glEnableVertexAttribArray(0);
-            glVertexAttribPointer(0, 2, GL_FLOAT, false, 24, 0);
+            glVertexAttribPointer(0, 2, GL_FLOAT, false, 12, 0);
 
 
             glEnableVertexAttribArray(2);  
             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)
     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)
     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);
             FloatBuffer newBuffer = BufferUtils.createFloatBuffer(buffer.capacity() * 2);
             buffer.flip();
             buffer.flip();
@@ -59,24 +54,15 @@ public class ColorRenderer
         
         
         buffer.put(x1);
         buffer.put(x1);
         buffer.put(y1);        
         buffer.put(y1);        
-        buffer.put(r);
-        buffer.put(g);
-        buffer.put(b);
-        buffer.put(a);
+        buffer.put(color);
         
         
         buffer.put(x2);
         buffer.put(x2);
         buffer.put(y2);        
         buffer.put(y2);        
-        buffer.put(r);
-        buffer.put(g);
-        buffer.put(b);
-        buffer.put(a);
+        buffer.put(color);
         
         
         buffer.put(x3);
         buffer.put(x3);
         buffer.put(y3);        
         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)
     public void addRectangle(float minX, float minY, float maxX, float maxY)
@@ -95,6 +81,8 @@ public class ColorRenderer
         glBindVertexArray(vao);
         glBindVertexArray(vao);
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
         glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
+        
+        buffer.limit(buffer.capacity());
         built = true;
         built = true;
     }
     }
     
     
@@ -106,6 +94,16 @@ public class ColorRenderer
         }
         }
         glBindVertexArray(vao);
         glBindVertexArray(vao);
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         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;
 package me.hammerle.snuviengine.api;
 
 
+import me.hammerle.snuviengine.game.Chunk;
 import java.util.Random;
 import java.util.Random;
-import static org.lwjgl.opengl.GL20.*;
 
 
 public class Map 
 public class Map 
 {
 {
     protected final static int PARTION = 16;
     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 layers;
     private int width;
     private int width;
     private int height;
     private int height;
@@ -18,48 +16,13 @@ public class Map
     private int pHeight;
     private int pHeight;
     private Chunk[][][] chunks = null;
     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)
     public void load(String path)
     {
     {
-        layers = 2;
+        /*layers = 2;
         width = 64;
         width = 64;
         height = 64;
         height = 64;
         tiles = new short[layers][width][height];
         tiles = new short[layers][width][height];
@@ -106,39 +69,7 @@ public class Map
                     chunks[l][x][y] = new Chunk();
                     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) 
     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
 public final class Shader
 {
 {
     private static int program = -1;
     private static int program = -1;
-    private static String[][] lightStrings;
     
     
     private static final List<Runnable> TASKS = new LinkedList<>();
     private static final List<Runnable> TASKS = new LinkedList<>();
     
     
     protected static boolean initDone = false;
     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()
     protected static void init()
     {
     {
         program = createShaderProgram("shaders/vertex.vs", "shaders/fragment.fs");
         program = createShaderProgram("shaders/vertex.vs", "shaders/fragment.fs");
         glUseProgram(program);
         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);
         setDepth(0.0f);
+        
+        unifAmbientLight = glGetUniformLocation(program, "ambientLight");
         setAmbientLight(1.0f, 1.0f, 1.0f);
         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);
             setLightColor(index, 0.0f, 0.0f, 0.0f);
             setLightLocation(index, 0.0f, 0.0f);
             setLightLocation(index, 0.0f, 0.0f);
             setLightStrength(index, 0.0f);
             setLightStrength(index, 0.0f);
         }
         }
         
         
+        unifUseTexture = glGetUniformLocation(program, "useTexture");
         setTextureUsing(false);
         setTextureUsing(false);
+        
+        unifUseColor = glGetUniformLocation(program, "useColor");
+        setColorUsing(false);
+        
+        unifUseLight = glGetUniformLocation(program, "useLight");
         setLightUsing(false);
         setLightUsing(false);
-        setCameraUsing(false);
         
         
         initDone = true;
         initDone = true;
     }
     }
@@ -62,7 +87,7 @@ public final class Shader
         }
         }
     }
     }
     
     
-    private static void sendMatrix()
+    private static void updateViewMatrix()
     {
     {
         FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
         FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
         
         
@@ -88,27 +113,57 @@ public final class Shader
         
         
         buffer.flip();
         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)
     public static void setDepth(float depth)
     {
     {
-        glUniform1f(glGetUniformLocation(program, "depth"), depth);
+        glUniform1f(unifDepth, depth);
     }
     }
     
     
     public static void setAmbientLight(float r, float g, float b)
     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)
     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");
             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)
     public static void setLightColor(int index, float r, float g, float b)
     {
     {
         checkLightIndex(index);
         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)
     public static void setLightLocation(int index, float x, float y)
     {
     {
         checkLightIndex(index);
         checkLightIndex(index);
-        glUniform2f(glGetUniformLocation(program, lightStrings[index][1]), x, y);
+        glUniform2f(unifLight[index][1], x, y);
     }
     }
     
     
     public static void setLightStrength(int index, float strength)
     public static void setLightStrength(int index, float strength)
     {
     {
         checkLightIndex(index);
         checkLightIndex(index);
-        glUniform1f(glGetUniformLocation(program, lightStrings[index][2]), strength);
+        glUniform1f(unifLight[index][2], strength);
     }
     }
     
     
     public static void setTextureUsing(boolean use)
     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);
         compiled = glGetProgrami(vfprogram, GL_LINK_STATUS);
         if(compiled != 1)
         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);
         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)
     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);
             FloatBuffer newBuffer = BufferUtils.createFloatBuffer(buffer.capacity() * 2);
             buffer.flip();
             buffer.flip();
@@ -76,6 +76,8 @@ public class TextureRenderer
         glBindVertexArray(vao);
         glBindVertexArray(vao);
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
         glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
+        
+        buffer.limit(buffer.capacity());
         built = true;
         built = true;
     }
     }
     
     
@@ -89,4 +91,14 @@ public class TextureRenderer
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         glDrawArrays(GL_TRIANGLES, 0, buffer.limit() / 4);
         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.ColorRenderer;
 import me.hammerle.snuviengine.api.Engine;
 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.KeyBinding;
 import me.hammerle.snuviengine.api.KeyHandler;
 import me.hammerle.snuviengine.api.KeyHandler;
 import me.hammerle.snuviengine.api.Shader;
 import me.hammerle.snuviengine.api.Shader;
 import me.hammerle.snuviengine.api.Texture;
 import me.hammerle.snuviengine.api.Texture;
 import me.hammerle.snuviengine.api.TextureRenderer;
 import me.hammerle.snuviengine.api.TextureRenderer;
+import me.hammerle.snuviengine.util.Clock;
 import static org.lwjgl.glfw.GLFW.*;
 import static org.lwjgl.glfw.GLFW.*;
 
 
 public class Game extends Engine
 public class Game extends Engine
@@ -20,6 +23,9 @@ public class Game extends Engine
     private final TextureRenderer tr = new TextureRenderer();
     private final TextureRenderer tr = new TextureRenderer();
     private final Texture t = new Texture("images/out3.png");
     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 x = 0.0f;
     float y = 0.0f;
     float y = 0.0f;
     
     
@@ -27,7 +33,7 @@ public class Game extends Engine
     
     
     public Game()
     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
     @Override
@@ -82,26 +88,82 @@ public class Game extends Engine
             counter = 0;
             counter = 0;
             t.nextFrame();
             t.nextFrame();
         }
         }
+        
+        x += 1f;
     }
     }
     
     
+    private static final Clock clock = new Clock(1000);
+    
     @Override
     @Override
     public void renderTick()
     public void renderTick()
     {
     {
         //Shader.drawMap();
         //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.build();
         cr.draw();
         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);
         Shader.setTextureUsing(true);
         t.bindTexture();
         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.addRectangle(i, 64, i + 64, 128, 0.0f, 0.0f, 1.0f, 1.0f);
         }
         }
         tr.build();
         tr.build();
         tr.draw();
         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);
+    }
+}