package de.rwth_aachen.graphics;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import org.lwjgl.opengl.GL11;

/**
 * Some provided data for rendering and testing VBOs.
 */
class Primitives
{
    /**
     * Create vertex data for a cube. The data will be structured as follows: (VxVyVzNxNyNz)* where VxVyVz are the vertex positions and NxNyNz are the normal vectors.
     * @return Vertices and normals of a cube.
     */
    public static FloatBuffer createCubeData() 
    {
        return FloatBuffer.wrap(new float[] {
            -1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f,
            -1.0f,  1.0f,  1.0f,  0.0f,  1.0f,  0.0f,
             1.0f,  1.0f,  1.0f,  0.0f,  1.0f,  0.0f,
             
             1.0f,  1.0f,  1.0f,  0.0f,  1.0f,  0.0f,
             1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f,
            -1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f,
            
            -1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f,
             1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f,
             1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f,
             
             1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f,
            -1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f,
            -1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f,
             
            -1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f,
             1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f,
             1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,
             
             1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,
            -1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,
            -1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f,
             
            -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f,
            -1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f,
             1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f,
             
             1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f,
             1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f,
            -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f,
            
             1.0f, -1.0f, -1.0f,  1.0f,  0.0f,  0.0f,
             1.0f,  1.0f, -1.0f,  1.0f,  0.0f,  0.0f,
             1.0f,  1.0f,  1.0f,  1.0f,  0.0f,  0.0f,
             
             1.0f,  1.0f,  1.0f,  1.0f,  0.0f,  0.0f,
             1.0f, -1.0f,  1.0f,  1.0f,  0.0f,  0.0f,
             1.0f, -1.0f, -1.0f,  1.0f,  0.0f,  0.0f,
                        
            -1.0f, -1.0f, -1.0f, -1.0f,  0.0f,  0.0f,
            -1.0f, -1.0f,  1.0f, -1.0f,  0.0f,  0.0f,
            -1.0f,  1.0f,  1.0f, -1.0f,  0.0f,  0.0f,
            
            -1.0f,  1.0f,  1.0f, -1.0f,  0.0f,  0.0f,
            -1.0f,  1.0f, -1.0f, -1.0f,  0.0f,  0.0f,
            -1.0f, -1.0f, -1.0f, -1.0f,  0.0f,  0.0f});
    }
    
    /**
     * Render immediate cube.
     */
    public static void drawCube() 
    {
        GL11.glBegin(GL11.GL_QUADS);
            GL11.glNormal3f(0.0f, 1.0f, 0.0f);
            GL11.glVertex3f(-1.0f, 1.0f, -1.0f);
            GL11.glVertex3f(-1.0f, 1.0f, 1.0f);
            GL11.glVertex3f(1.0f, 1.0f, 1.0f);
            GL11.glVertex3f(1.0f, 1.0f, -1.0f);
            
            GL11.glNormal3f(0.0f, -1.0f, 0.0f);
            GL11.glVertex3f(-1.0f, -1.0f, -1.0f);
            GL11.glVertex3f(1.0f, -1.0f, -1.0f);
            GL11.glVertex3f(1.0f, -1.0f, 1.0f);
            GL11.glVertex3f(-1.0f, -1.0f, 1.0f);
            
            GL11.glNormal3f(0.0f, 0.0f, 1.0f);
            GL11.glVertex3f(-1.0f, -1.0f, 1.0f);
            GL11.glVertex3f(1.0f, -1.0f, 1.0f);
            GL11.glVertex3f(1.0f, 1.0f, 1.0f);
            GL11.glVertex3f(-1.0f, 1.0f, 1.0f);
            
            GL11.glNormal3f(0.0f, 0.0f, -1.0f);
            GL11.glVertex3f(-1.0f, -1.0f, -1.0f);
            GL11.glVertex3f(-1.0f, 1.0f, -1.0f);
            GL11.glVertex3f(1.0f, 1.0f, -1.0f);
            GL11.glVertex3f(1.0f, -1.0f, -1.0f);
            
            GL11.glNormal3f(1.0f, 0.0f, 0.0f);
            GL11.glVertex3f(1.0f, -1.0f, -1.0f);
            GL11.glVertex3f(1.0f, 1.0f, -1.0f);
            GL11.glVertex3f(1.0f, 1.0f, 1.0f);
            GL11.glVertex3f(1.0f, -1.0f, 1.0f);
            
            GL11.glNormal3f(-1.0f, 0.0f, 0.0f);
            GL11.glVertex3f(-1.0f, -1.0f, -1.0f);
            GL11.glVertex3f(-1.0f, -1.0f, 1.0f);
            GL11.glVertex3f(-1.0f, 1.0f, 1.0f);
            GL11.glVertex3f(-1.0f, 1.0f, -1.0f);
        GL11.glEnd();
    }
    
    /**
     * Render immediate quad with texture coordinates.
     */
    public static void drawQuad() 
    {
        GL11.glBegin(GL11.GL_QUADS);
            GL11.glNormal3f(0.0f, 0.0f, 1.0f);
            GL11.glTexCoord2f(0.0f, 0.0f);
            GL11.glVertex3f(-1.0f, -1.0f, 0.0f);
            GL11.glTexCoord2f(1.0f, 0.0f);
            GL11.glVertex3f(1.0f, -1.0f, 0.0f);
            GL11.glTexCoord2f(1.0f, 1.0f);
            GL11.glVertex3f(1.0f, 1.0f, 0.0f);
            GL11.glTexCoord2f(0.0f, 1.0f);
            GL11.glVertex3f(-1.0f, 1.0f, 0.0f);
        GL11.glEnd();
    }
    
    /**
     * Render immediate grid.
     * @param repetitions Number of lines to be drawn in each direction.
     * @param increment Distance between the lines.
     */
    public static void drawGrid(int repetitions, float increment) 
    {
        float size = repetitions * increment;
        GL11.glBegin(GL11.GL_LINES);
            for(int i = -repetitions; i <= repetitions; i++)
            {
                GL11.glVertex3f(-size, 0.0f, i * increment);
                GL11.glVertex3f( size, 0.0f, i * increment);
            }
            for(int i = -repetitions; i <= repetitions; i++)
            {
                GL11.glVertex3f(i * increment, 0.0f, -size);
                GL11.glVertex3f(i * increment, 0.0f,  size);
            }
        GL11.glEnd();
    }

    public static void drawQuad(float xStart, float xSize, float yStart, float ySize, float sStart, float sSize, float tStart, float tSize){
        GL11.glBegin(GL11.GL_QUADS);
        GL11.glTexCoord2f(sStart+sSize, tStart);
        GL11.glVertex2f(xStart+xSize, yStart);
        GL11.glTexCoord2f(sStart+sSize, tStart+tSize);
        GL11.glVertex2f(xStart+xSize, yStart+ySize);
        GL11.glTexCoord2f(sStart, tStart+tSize);
        GL11.glVertex2f(xStart, yStart+ySize);
        GL11.glTexCoord2f(sStart, tStart);
        GL11.glVertex2f(xStart, yStart);
        GL11.glEnd();
    }
    public static void drawQuadStrip(int count, float xStart, float xSize, float yStart, float ySize, float sStart, float sSize, float tStart, float tSize){
        if (count==0) return;
        else if (count==1) drawQuad(xStart,xSize,yStart,ySize,sStart,sSize,tStart,tSize);
        else {
            GL11.glBegin(GL11.GL_QUAD_STRIP);
            for (int i=0;i<=count;i++){
                GL11.glTexCoord2f(sStart, tStart+i*tSize);
                GL11.glVertex2f(xStart, yStart+i*ySize);
                GL11.glTexCoord2f(sStart+sSize, tStart+i*tSize);
                GL11.glVertex2f(xStart+xSize, yStart+i*ySize);
            }
            GL11.glEnd();
        }
    }
}
