/*
Copyright (C) 2019 Taisuke Kobayashi
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
void draw_object(){
}

// 以下はlibrary。説明があるまで理解しなくても大丈夫。

final float f_alen = 200;
final int f_width = 600, f_height = f_width; 
final float f_fovy = radians(60), f_aspect = 1, f_near = 1, f_far = 1000;
final float f_eye_rotate_w = 0.2; // weight
final float f_eye_translate_w = 0.1;
final float f_eye_dist_w = 0.2;
final float f_eye_dist_min = 10.0;
final float f_down_rotate_w = 0.001;
PVector g_eye = new PVector(0, 0, -f_alen);
PVector g_center = new PVector(0, 0, 0);
PVector g_down =  new PVector(0, -1, 0);

void sankaku(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3){
  noStroke();
  beginShape(TRIANGLES);
  vertex(x1, y1, z1);
  vertex(x2, y2, z2);
  vertex(x3, y3, z3);
  endShape();
}

void kyuu(float x, float y, float z, float r){
  noStroke();
  pushMatrix();
  translate(x, y, z);
  sphere(r);
  popMatrix();     
}

void origin_center(){
  strokeWeight(1);
  stroke(255, 255, 0);
  beginShape(LINES);
  vertex(0, 0, 0);
  vertex(g_center.x, g_center.y, g_center.z);
  endShape();
  noStroke();
}

void axis(){
  strokeWeight(1);
  beginShape(LINES);
  stroke(255, 0, 0);
  vertex(0, 0, 0);
  vertex(f_alen, 0, 0);
  stroke(0, 255, 0);
  vertex(0, 0, 0);
  vertex(0, f_alen, 0);
  stroke(0, 0, 255);
  vertex(0, 0, 0);
  vertex(0, 0, f_alen);
  endShape();
}

void setup(){
  size(f_width, f_height, P3D);
}

void draw_background(){
  background(0);
  camera(g_eye.x, g_eye.y, g_eye.z, g_center.x, g_center.y, g_center.z, g_down.x, g_down.y, g_down.z);
  perspective(f_fovy, f_aspect, f_near, f_far);
  lights();
}

void draw(){
  draw_background();
  origin_center();
  axis();
  draw_object();
}

void print_debug_info(){
  System.out.println("eye " + g_eye.x + " " + g_eye.y + " " + g_eye.z);
}

void adjust_down(){
  PVector a = PVector.sub(g_center, g_eye);
  PVector b = a.cross(g_down);
  PVector c = b.cross(a);
  c.normalize();
  g_down = c;
}

void eye_rotate(){
  float dist = g_center.dist(g_eye);
  float dx = (mouseX - pmouseX) * f_eye_rotate_w;
  float dy = (mouseY - pmouseY) * f_eye_rotate_w;
  PVector a = PVector.sub(g_center, g_eye).cross(g_down);
  a.normalize();
  g_eye.add(PVector.mult(a, dx) );
  g_eye.add(PVector.mult(g_down, dy) );
  a = PVector.sub(g_eye, g_center);
  a.normalize();
  a.mult(dist);
  a.add(g_center);
  g_eye = a;
  adjust_down();
}

void eye_translate(){
  float dx = (mouseX - pmouseX) * f_eye_translate_w;
  float dy = (mouseY - pmouseY) * f_eye_translate_w;
  PVector a = PVector.sub(g_center, g_eye).cross(g_down);
  a.normalize();
  PVector b = PVector.mult(a, dx);
  b.add(PVector.mult(g_down, dy) );
  g_eye.add(b);
  g_center.add(b);
}

void eye_dist_and_down_rotate(){
  float dx = (mouseX - pmouseX) * f_down_rotate_w;
  float dy = (mouseY - pmouseY) * f_eye_dist_w;
  PVector a = PVector.sub(g_eye, g_center);
  a.normalize();
  a.mult(dy);
  PVector b = PVector.add(g_eye, a);
  if(b.dist(g_center) > f_eye_dist_min)
    g_eye = b;
  a = PVector.sub(g_center, g_eye).cross(g_down);
  a.normalize();
  a.mult(dx);
  g_down.add(a);
  adjust_down();
}

void mouseDragged(){
  switch(mouseButton){
  case LEFT:
    if(keyPressed == true && key == CODED){
      switch(keyCode){
      case CONTROL:
        eye_translate();
        break;
      case ALT:
        eye_dist_and_down_rotate();
        break;
      case SHIFT:
        break;
      }
    }else{
      eye_rotate();
    }
    break;
  case CENTER:
    eye_dist_and_down_rotate();
    break;
  case RIGHT:
    eye_translate();
    break;
  }
}
