//
// A GLSL / OpenGL 3.x version of the "dist2d.tks" software rendering example
//  (c) 2011-12-29 by Bastian Spiegel
//

use tksdl;
use tkopengl;

int numframesrendered;

float t;

class Dist2d_GLSL {
   Texture tex;
   FloatArray attractors;
   FloatArray attractor_rotations;

   define int NUM_ATTRACTORS = 8;

   // (note) ftransform() is deprecated after version 1.20 but I'm just too lazy right now to set up my own matrices ;)
   String vert_src = "void main() { gl_Position = ftransform(); }";

   String frag_src;
   
   int program;
   int vert;
   int frag;
   int uni_viewport_sx;
   int uni_viewport_sy;
   IntArray uni_attractors;
   

   public method init() {
      // center points
      attractors.alloc(NUM_ATTRACTORS * 2);
      loop(NUM_ATTRACTORS)
      {
         attractors.add(0.5);
         attractors.add(0.5);
      }

      // rotations
      attractor_rotations.alloc(NUM_ATTRACTORS * 4);
      loop(NUM_ATTRACTORS)
      {
         attractor_rotations.add(0);
         attractor_rotations.add(rnd(0.0123123)+0.0123123);

         attractor_rotations.add(0);
         attractor_rotations.add(rnd(0.0234234) + 0.0123123);
      }

      // Load fragment shader source
      frag_src.load("dist2d_glsl.frag", true);
   }

   public method onReopen() {
      String log;

      program = glCreateProgram();

      vert = glCreateShader(GL_VERTEX_SHADER);
      zglShaderSource(vert, vert_src);
      glCompileShader(vert);
      glGetShaderInfoLog(vert, log);
      trace "[...] vertex shader log=\""+log+"\".";
      glAttachShader(program, vert);

      frag = glCreateShader(GL_FRAGMENT_SHADER);
      zglShaderSource(frag, frag_src);
      glCompileShader(frag);
      glGetShaderInfoLog(frag, log);
      trace "[...] fragment shader log=\""+log+"\".";
      glAttachShader(program, frag);

      glBindFragDataLocation(program, 0, "fragColor");

      glLinkProgram(program);

      glGetProgramInfoLog(program, log);
      trace "[...] program log=\""+log+"\".";

      glUseProgram(program);
      uni_viewport_sx = glGetUniformLocation(program, "viewport_sx");
      uni_viewport_sy = glGetUniformLocation(program, "viewport_sy");
      glUniform1f(uni_viewport_sx, Viewport.width);
      glUniform1f(uni_viewport_sy, Viewport.height);

      int k = 0;
      uni_attractors.empty();
      loop(NUM_ATTRACTORS*2)
      {
         int loc = glGetUniformLocation(program, "attractors["+k+"]");
         uni_attractors.add(loc);
         k++;
      }
   }

   public method draw(float dt) {
      glColor3f(0.9,0.9,0.9);

      glUseProgram(program);

      // Update attractor position uniforms
      int k = 0;
      loop(NUM_ATTRACTORS*2)
      {
         glUniform1f(uni_attractors[k], attractors[k]);
         k++;
      }

      zglInitOrtho(-1,1);
      glBegin(GL_QUADS);
      glTexCoord2f(0, 0);
      glVertex2f(-1,-1);
      glTexCoord2f(1, 0);
      glVertex2f( 1,-1);
      glTexCoord2f(1, 1);
      glVertex2f( 1, 1);
      glTexCoord2f(0, 1);
      glVertex2f(-1, 1);
      glEnd();

      glUseProgram(0);

      // animate attractors
      int i = 0;
      int j = 0;
      loop(NUM_ATTRACTORS)
      {
         float v = attractor_rotations[j];
         v += attractor_rotations[j+1] * dt;
         wrap v 0 2PI;
         attractor_rotations[j] = v;
         attractors[i] = 0.5 + sin(v) * 0.5;

         v = attractor_rotations[j+2];
         v += attractor_rotations[j+3] * dt;
         wrap v 0 2PI;
         attractor_rotations[j+2] = v;
         attractors[i+1] = 0.5 + sin(v) * 0.5;

         i += 2;
         j += 4;
      }
   }

}

Dist2d_GLSL dist2d;


function onDraw() {
   float dt=FPS.precision;
   // glClearColor(0,0,0.2,1);
   // glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
   if( !(++numframesrendered&127) )
      trace "FPS.real="+FPS.real;

   dist2d.draw(dt);
}

function onMouse(int _x, int _y, int _cbs, int _nbs) {
   //print "x="+_x+" y="+_y+" cbs="+_cbs+" nbs="+_nbs;
}

function onKeyboard(Key _k) {
   switch(_k.pressed)
   {
      case VKEY_ESCAPE:
         SDL.exitEventLoop();
         break;
   }
}

function onReopen() {

   dist2d.onReopen();
}

function main() {
   Viewport.openWindow(640, 480);
   //Viewport.openWindow(128, 128);

   // Viewport.enableGLError = true;

   trace "[...]                   GL_VENDOR = \"" + glGetString(GL_VENDOR) + "\"";
   trace "[...]                  GL_VERSION = \"" + glGetString(GL_VERSION) + "\"";
   trace "[...] GL_SHADING_LANGUAGE_VERSION = \"" + glGetString(GL_SHADING_LANGUAGE_VERSION) + "\"";

   use callbacks;

   zglLoadExtensions();

   FPS.tickInterval=16;
   FPS.limit=60;

   dist2d.init();

   onReopen();

   Viewport.swapInterval(1);

   trace "xxx entering eventloop";
   SDL.eventLoop();
}