#include "rogueviz.h"

// 'hyperbolic city' demo
// download the model from https://sketchfab.com/3d-models/night-city-p2-82637933a7cb4fafadb0e2a79415c438 as rogueviz/models/emilejohansson_p2.obj

// see the results posted here:

// https://twitter.com/ZenoRogue/status/1375750351391981570
// -hypcity -noplayer -geo 4x5 -gp 1 1 -unrectified -switch-fpp -canvas 303030 camera=0 depth=0 -sr 3 -PM 0 -alpha 1 -zoom .95

// https://twitter.com/ZenoRogue/status/1375748835046215682
// -hypcity -noplayer -geo nil -canvas 303030 -back 44e4 -sight3 3

// https://twitter.com/ZenoRogue/status/1375754422752575488
//  add -PM 0 -alpha 1

namespace hr {
#if CAP_MODELS
namespace hypcity {

using namespace rogueviz::objmodels;

void prepare_tf();

struct citymodel : model {
  citymodel() : model("rogueviz/models/", "emilejohansson_p2.obj") {}

  hyperpoint low, high;
  ld t;

  void prepare() override {
    for(int i=0; i<4; i++) low[i] = 100, high[i] = -100;

    cgi.require_basics();
    hyperpoint corner = get_corner_position(cwt.at, 0);
    
    t = abs(corner[0] / corner[3]);
    }

  hyperpoint transform(hyperpoint h) override {
    swap(h[1], h[2]);
    h[2] = -h[2];
    h[2] += 0.063;
    h[0] -= 0.063;
    h[1] += 0.063;
    h *= 6;
    // h[0] -= .5;
    // h[1] += .5;

    for(int i=0; i<4; i++)
      low[i] = min(low[i], h[i]),
      high[i] = max(high[i], h[i]);
      
    if(hyperbolic || sphere) {
    
      hyperpoint hx;
      hx[0] = h[0] * t * 2;
      hx[1] = h[1] * t * 2;
      hx[2] = 0;
      hx[3] = 1;
      if(hyperbolic) hx = spin(45._deg) * hx;
      hx = normalize(hx);
      hx = orthogonal_move(hx, h[2]*(t*(sphere ? 3 : 7)));

      return hx;
      }
    
    if(nil || sol) {
      if(nil) swap(h[1], h[2]);
      h *= 0.5 / 0.378;
      if(sol) h *= vid.binary_width;
      if(nil) h *= nilv::nilwidth;
      h[3] = 1;
      return h;
      }
    
    return h;
    }

  void postprocess() override {
    println(hlog, "low = ", low);
    println(hlog, "high = ", high);
    }
  };

citymodel city;

bool draw_city_at(cell *c, const shiftmatrix& V) {
  if(nil) {
    auto co = nilv::get_coord(c->master);
    if(co[1]) return false;
    }

  if(sol) {
    auto co = c->master->distance;
    if(co) return false;
    }
  
  if(c == cwt.at || true) 
    city.render(V);

  return false;
  }

void enable() { 
  rogueviz::rv_hook(hooks_drawcell, 100, draw_city_at); 
  add_model_settings();
  }

auto hypcity_ah = arg::add3("-hypcity", enable)
+ addHook_slideshows(120, [] (tour::ss::slideshow_callback cb) {

    using namespace rogueviz::pres;
    static vector<slide> hypcity_slides;

    if(hypcity_slides.empty()) {
      hypcity_slides.emplace_back(
        slide{"Introduction", 999, LEGAL::NONE, 
          "Here we put a 3D model of a city into various geometries. Don't forget to try changing RogueViz projection and view range settings!\n\n"
          "Remember to try different projections (press '1')!"
          ,
          [] (presmode mode) {
          slide_url(mode, 'm', "original model by Emile Johansson", "https://sketchfab.com/3d-models/night-city-p2-82637933a7cb4fafadb0e2a79415c438");
          slide_url(mode, 't', "original Tweets by Nico Belmonte", "https://twitter.com/philogb/status/1375147728389476356");
          }});
      
      auto add = [&] (string s, string text, int dim, reaction_t setter) {
        hypcity_slides.emplace_back(
          tour::slide{s, 100, LEGAL::NONE | QUICKGEO, text,
            [=] (presmode mode) {
              if(mode == pmStart && dim == 2 && !vid.always3) {
                geom3::switch_fpp();
                }
              setCanvas(mode, '0');
              if(mode == pmStart) {
                slide_backup(canvas_default_wall, waInvisibleFloor);
                if(dim == 2) slide_backup(vid.camera, 0);
                if(dim == 2) slide_backup(vid.depth, 0);
                slide_backup(context_fog, false);
                setter();
                start_game();
                enable();
                }
              non_game_slide_scroll(mode);
              }});
        };
      
      add("hyperbolic", "Hyperbolic geometry.", 2, [] {
        set_geometry(g45);
        gp::param = {1, 1};
        set_variation(eVariation::unrectified);
        });
      add("spherical", "Spherical geometry.", 2, [] {
        set_geometry(gSmallSphere);
        set_variation(eVariation::pure);
        });
      add("Nil", "Nil geometry.", 3, [] {
        set_geometry(gNil);
        });
      add("Solv", "Solv geometry.", 3, [] {
        set_geometry(gSol);
        });
      add_end(hypcity_slides);
      }

    cb(XLAT("non-Euclidean city"), &hypcity_slides[0], 'c');
    });

}
#endif
}