///////////////
  //// set destroyer
  public void initDestroyer() {

    //// init the destroyer
    //// placeholder lat and long
    float lt = new Float(4.6);
    float lo = new Float(-74.0833);

    try {
      theDestroyer = new Destroyer(lo, lt);
      theDestroyer.computePosOnSphere(EARTH_RADIUS);

    } catch (Exception e) {
      println(e);
    }
  }
  public void oscEvent(OscMessage theOscMessage) {
    // print the address pattern of the received OscMessage
    String addr = theOscMessage.addrPattern();

    print("### received an osc message.");
    println("tag type: " + theOscMessage.typetag());
    println("addr type: " + theOscMessage.addrPattern()); // it was lowercase in the documentation

    /// we have to check for init OSC values
    /// so the mouse doesn't override it on
    /// globe and cursor postion
    if (addr.indexOf("/EpsonPlanet/xy1") != -1) {
      hasOsc = true;
      println(hasOsc);
    }
    if (addr.indexOf("/EpsonPlanet/xy2") != -1) {
      hasOsc = true;
      println(hasOsc);
    }

    if (theOscMessage.checkTypetag("i")) {
      if (addr.equals("/EpsonPlanet/fader1")) {
        int valI = theOscMessage.get(0).intValue();
      }
    }

    /// check for 2 FLOATS
    if (theOscMessage.checkTypetag("ff")) {
      float val0 = theOscMessage.get(0).floatValue();
      float val1 = theOscMessage.get(1).floatValue();
      // hasOsc == true
      println("FF type: " + val0 + " " + val1);
      try {
        if (addr.equals("/EpsonPlanet/xy1")) {
          println("Do globe " + val0);
          oscX0 = new Float(val0);
          oscY0 = new Float(val1);
        } else if (addr.equals("/EpsonPlanet/xy2")) {
          float val2 = theOscMessage.get(0).floatValue();
          float val3 = theOscMessage.get(1).floatValue();
          doCursor = true;
          oscX1 = new Float(val2);
          oscY1 = new Float(val3);
        }
      } catch (Exception e) {
        println("can't run real floats");
      }
    }
    /// check for ONE FLOAT
    /// thanks stupid oscP5
    if (theOscMessage.checkTypetag("f")) {
      /// set up strings for the 2 values because stupid OSC
      String str0 = theOscMessage.toString();
      String str1 = theOscMessage.toString();

      try {

        // println(" VALUE 0: "+theOscMessage.get(0).floatValue());
        if (addr.equals("/EpsonPlanet/fader1")) {
          // targetZoom = max(targetZoom - 0.1f, 0.5f);
          // targetZoom = min(targetZoom + 0.1f, 1.9f);
          float val0 = theOscMessage.get(0).floatValue();
          println("DO ZOOM " + addr + " " + val0);
          targetZoom = map(val0, 0, 1, 0.5f, 1.9f);

        } else if (addr.equals("/1/fader2")) {
          println("v2 " + str0);
        } else if (addr.equals("/1/xy1")) {

        } else if (addr.equals("/EpsonPlanet/toggle1")) {
          println("toggle visibility");
          theDestroyer.toggleVisibility();

        } else if (addr.equals("/EpsonPlanet/resetGlobeButt")) {
          println("reset position");
          theCamX = defaultCamX;
          theCamY = defaultCamY;
          targetZoom = 1;

        } else if (addr.equals("/EpsonPlanet/playVidButt")) {
          println("play vid");
          thePopUp.startVideo();

        } else if (addr.equals("/EpsonPlanet/stopVidButt")) {
          println("pause vid");
          thePopUp.stopVideo();

        } else if (addr.equals("/EpsonPlanet/rotary1")) {
          int v = parseInt(theOscMessage.get(0).floatValue());
          println("R: " + v + " " + str0);
          bgColorR = v;
        } else if (addr.equals("/EpsonPlanet/rotary2")) {
          int v = parseInt(theOscMessage.get(0).floatValue());
          println("G: " + v + " " + str0);
          bgColorG = v;
        } else if (addr.equals("/EpsonPlanet/rotary3")) {
          int v = parseInt(theOscMessage.get(0).floatValue());
          println("B: " + v + " " + str0);
          bgColorB = v;
        }
      } catch (Exception e) {
        println(" osc error: " + e);
      }
    }

    /// control x and y globe

    /// control x and y destroyer
  }
  public void setDestroyer() {
    // convert cur mouse pos to lat and long
    // map(value, low1, high1, low2, high2)

    if (doCursor == true) {
      // theLat = map(oscY1, 1, 0, 0, 90);
      // theLong = map(oscX1, 0, 1, -180, 180);

      /// change osc values to mouse-parsed
      float newOscY = map(oscY1, 0, 1, 0, screenHeight);
      float newOscX = map(oscX1, 0, 1, 0, screenWidth);

      desRot.interpolateToSelf(new Vec3D(newOscX * 0.51f, newOscY * 0.51f, 0), 0.25f / currZoom);
      theLat = desRot.y; // map(mouseY, 0, screenHeight, 0, 90);
      theLong = desRot.x; // map(mouseX, 0, screenWidth, -180, 180);

    } else {
      // theLat = map(mouseY, 600, 0, 0, 90);
      // theLong = map(mouseX, 200, 800, -180, 180);

    }
    if (!mousePressed && useKeyboard == true) {

      /// *
      desRot.interpolateToSelf(new Vec3D(mouseX * 0.51f, mouseY * 0.51f, 0), 0.25f / currZoom);
      theLat = desRot.y; // map(mouseY, 0, screenHeight, 0, 90);
      theLong = desRot.x; // map(mouseX, 0, screenWidth, -180, 180);
      // */

    }
    doCursor = false;

    /*
    * theCamX = camRot.x;
    theCamY = camRot.y;
    */

    //

    theDestroyer.setSpherePosition(theLong, theLat);
    theDestroyer.computePosOnSphere(EARTH_RADIUS);

    //// CHECK FOR INTERSECTION with other markers
    boolean isPopupVisible = false;
    for (int i = 0; i < GPSArray.size(); i++) {
      // for(int i=0; i<2; i++){

      /// DESTROYER LAT AND LONG
      float dlat = theDestroyer.theLat;
      float dlong = theDestroyer.theLong; // theDestroyer.theLat;

      //// MARKER LAT AND LONG
      float mlat = GPSArray.get(i).theLat;
      float mlong = GPSArray.get(i).theLong;
      // println("dlat " + dlat + " mlat: " + mlat);
      // println("dlong " + dlong + " mlong: " + mlong);
      //// check to see if the destroyer is within the range of the current lat and long
      /// if (dlat >= (mlat -1) && dlat <= (mlat + 1) &&  dlong <= (mlong + 1) && dlong >= (mlong -
      // 1)){

      //// CHECK INTERSECTION of MARKER AND DESTROYER
      GPSMarker tMark = GPSArray.get(i);
      if (isPopupVisible == false
          && theDestroyer.pos.y <= (tMark.pos.y + 10)
          && theDestroyer.pos.y >= (tMark.pos.y - 10)
          && theDestroyer.pos.x <= (tMark.pos.x + 10)
          && theDestroyer.pos.x >= (tMark.pos.x - 10)) {

        tMark.doHit();

        //// init popup data
        thePopUp.theName = "";
        thePopUp.theText = "";

        thePopUp.theHeader = headerList.get(tMark.theID);
        thePopUp.theName = nameList.get(tMark.theID);
        thePopUp.theText = blurbList.get(tMark.theID);
        // thePopUp.theVideoPath = videoPathList.get(tMark.theID);

        /// swtich video if it's different than the current
        if (curID != tMark.theID) {
          // println("Cur ID: " + curID + " new ID: " + tMark.theID);
          /// stop current, switch
          thePopUp.stopVideo();
          thePopUp.switchCurVideo(tMark.theID);
          curID = tMark.theID;
        }

        //// showing popup data
        thePopUp.drawPopup(tMark.theID);
        isPopupVisible = true;
      }
    }
  }
  ///////////////////////////////
  /// GLOBE RENDERING
  ////////////////////////////////
  private void renderGlobe() {
    // smoothly interpolate camera rotation
    // to new rotation vector based on mouse position
    // each frame we only approach that rotation by 25% (0.25 value)

    lights();
    /* this looks pink
    ambientLight(255, 0, 0);
    specular(255, 0, 0);
    */
    // store default 2D coordinate system
    pushMatrix();
    // switch to 3D coordinate system and rotate view based on mouse
    translate(width / 2, height / 2, 0);

    ///// CHECK FOR MOUSE INPUT TO SET CAMERA
    if (mousePressed) {
      camRot.interpolateToSelf(new Vec3D(mouseY * 0.01f, mouseX * 0.01f, 0), 0.25f / currZoom);
      // println("MOUSEX: " + mouseX);
      // println("MouseY " + mouseY);
      theCamX = camRot.x;
      theCamY = camRot.y;

      ///// CHECK FOR OSC INPUT TO SET CAMERA
    } else if (hasOsc == true) {
      /// map(value, low1, high1, low2, high2)

      println("rotate dammit!");
      float newX = map(oscX0, 0, 1, 0, screenWidth); // /// maps our input to 1024
      float oscY = map(oscY0, 0, 1, 0, screenHeight); // ///
      camRot.interpolateToSelf(new Vec3D(oscY * 0.01f, newX * 0.01f, 0), 0.25f / currZoom);
      theCamX = camRot.x;
      theCamY = camRot.y;
      // rotateX(camRot.x);
      // rotateY(camRot.y);
      // currZoom += (targetZoom - currZoom) * 0.25;
      // */

    }

    theOldCamX = theCamX;
    theOldCamY = theCamY;

    hasOsc = false; // /switch off osc input until we get another osc signal
    float newCamX =
        map(new Float(theCamX), 0, 7, 2, 4); // narrow the range of vertical camera movement

    currZoom += (targetZoom - currZoom) * 0.25;
    // theCamX = newCamX;

    rotateX(new Float(theCamX));
    rotateY(new Float(theCamY));

    // apply zoom factor
    scale(currZoom);
    // compute the normalized camera position/direction
    // using the same rotation setting as for the coordinate system
    // this vector is used to figure out if images are visible or not
    // (see below)
    Vec3D camPos =
        new Vec3D(0, 0, 1)
            .rotateX(new Float(theCamX))
            .rotateY(new Float(theCamY)); // / changed from cam.x and cam.y
    camPos.normalize();
    noStroke();
    fill(255);
    // use normalized UV texture coordinates (range 0.0 ... 1.0)
    textureMode(NORMAL);
    // draw earth
    gfx.texturedMesh(globe, earthTex, true);

    ////////////////////////////////////////
    // /// SET GPS MARKERS ON THE SPHERE

    // check marker position
    for (int i = 0; i < GPSArray.size(); i++) {
      GPSArray.get(i).updateScreenPos(this, camPos);
    }
    // check destroyer position
    if (isVideoPlaying == false) {
      // if(thePopUp.isVideoPlaying == true){
      theDestroyer.updateScreenPos(this, camPos);
    }

    /////////////////////////////////////////
    // switch back to 2D coordinate system
    popMatrix();
    // disable depth testing to ensure anything drawn next
    // will always be on top/infront of the globe
    hint(DISABLE_DEPTH_TEST);
    // draw images centered around the given positions
    imageMode(CENTER);

    // now that they're in position, draw them
    for (int i = 0; i < GPSArray.size(); i++) {
      GPSArray.get(i).drawAsImage(IMG_SIZE * currZoom * 0.9f, showLabels);
    }
    // draw the destroyer
    try {
      theDestroyer.drawAsImage(this, IMG_SIZE * currZoom * 0.9f, showLabels);
    } catch (Exception e) {
      println("Cant draw destroyer" + e);
    }
    setDestroyer();
    ////////////////////////////////////////
    // restore (default) depth testing
    hint(ENABLE_DEPTH_TEST);
  }