public void onDrawFrame(GL10 gl) {

    if (Util.touchTurn != 0) {
      obj1.rotateY(Util.touchTurn);
      Util.touchTurn = 0;
    }

    if (Util.touchTurnUp != 0) {
      obj1.rotateX(Util.touchTurnUp);
      Util.touchTurnUp = 0;
    }

    fb.clear(back);
    world.renderScene(fb);
    world.draw(fb);
    fb.display();

    if (System.currentTimeMillis() - time >= 1000) {
      Logger.log(fps + "fps");
      fps = 0;
      time = System.currentTimeMillis();
    }
    fps++;
  }
  protected void loop() throws Exception {
    while (isShowing()) {
      if (!paused) {
        buffer.clear(java.awt.Color.BLACK);
        world.renderScene(buffer);
        world.draw(buffer);

        camera.performMovement();
        buffer.update();
        buffer.display(canvas.getGraphics());
        canvas.repaint();

        if (System.currentTimeMillis() - startTime >= delay) {
          startTime = System.currentTimeMillis();
          wb.update();
        }
      }
      this.requestFocus();
    }
    buffer.disableRenderer(IRenderer.RENDERER_OPENGL);
    buffer.dispose();
    dispose();
    System.exit(0);
  }
  public void onSurfaceChanged(GL10 gl, int w, int h) {
    if (frameBuffer != null) frameBuffer.dispose();

    frameBuffer = new FrameBuffer(gl, w, h);

    // 載入模型
    arch = loadModel("Arch.3DS", 15);
    arch.compile();
    box = loadModel("Box.3DS", 8);
    box.compile();
    cylinder = loadModel("Cylinder.3DS", 7);
    cylinder.compile();

    arch.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
    box.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
    cylinder.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);

    arch.setName("Arch");
    box.setName("Box");
    cylinder.setName("Cylinder");

    // 設定世界場景(加入3個模型)
    world = new World();
    world.setAmbientLight(75, 75, 75);
    world.addObject(arch);
    world.addObject(box);
    world.addObject(cylinder);

    box.translate(new SimpleVector(-15, -20, 5));
    arch.translate(new SimpleVector(-15, 5, -5));

    // 記錄原始位置
    archOriginPosition = arch.getTranslation();
    boxOriginPosition = box.getTranslation();
    cylinderOriginPosition = cylinder.getTranslation();

    // 設定Camera
    Camera camera = world.getCamera();
    camera.moveCamera(Camera.CAMERA_MOVEOUT, 50); // 向後移50
    camera.lookAt(SimpleVector.ORIGIN); // 看向(0,0,0)

    // 設定Light
    sun = new Light(world);
    sun.setIntensity(175, 175, 175);
    sun.setPosition(camera.getPosition());

    MemoryHelper.compact();
  }
  private void Handle3DControl(Object3D obj, float originZ) {
    switch (Activity3Page.currentActionType) {
      case Move:
        // ---處理移動(Translate Position: X,Y)---begin
        SimpleVector transPos =
            new SimpleVector(
                obj.getTranslation().x + deltaTranslatePositionX,
                obj.getTranslation().y + deltaTranslatePositionY,
                obj.getTranslation().z);

        SimpleVector projectScreenV3 =
            Interact2D.project3D2D(
                world.getCamera(), frameBuffer, transPos); // (重要!!!)這可以知道3D物件在2D畫面的投影

        if (projectScreenV3.x >= 0
            && projectScreenV3.y >= 0
            && projectScreenV3.x <= frameBuffer.getWidth()
            && projectScreenV3.y <= frameBuffer.getHeight()) {
          obj.translate(deltaTranslatePositionX, deltaTranslatePositionY, 0);
        }
        deltaTranslatePositionX = 0;
        deltaTranslatePositionY = 0;
        // ---處理移動(Translate Position: X,Y)---end

        // ---處理放大縮小(Scale)---begin
        if (deltaScale != 0) {
          float currentScale = obj.getScale() + deltaScale;
          if (currentScale <= 0.5f) {
            obj.setScale(0.5f);
          } else if (currentScale >= 1.5f) {
            obj.setScale(1.5f);
          } else {
            obj.setScale(currentScale);
          }
          deltaScale = 0;
        }
        // ---處理放大縮小(Scale)---end
        break;

      case Rotate:
        // ---處理旋轉(Rotate)---begin
        if (deltaRotateAngleX != 0) {
          obj.rotateY(deltaRotateAngleX);
          deltaRotateAngleX = 0;
        }
        if (deltaRotateAngleY != 0) {
          obj.rotateX(deltaRotateAngleY);
          deltaRotateAngleY = 0;
        }
        // ---處理旋轉(Rotate)---end
        break;

      case Depth:
        // ---處理深度(Translate Depth: Z軸)---begin
        float currentPosZ = obj.getTranslation().z + deltaTranslatePositionZ;
        if (currentPosZ > originZ - ZaxisCanMoveDistance
            && currentPosZ < originZ + ZaxisCanMoveDistance) {
          obj.translate(0, 0, deltaTranslatePositionZ);
        }
        deltaTranslatePositionZ = 0;
        // ---處理深度(Translate Depth: Z軸)---end
        break;
    }
  }
  public void onDrawFrame(GL10 gl) {

    // 程式已精簡過,備註:此部分必須寫在GL端,getPixel不能跳脫GL執行緒內
    // 錯誤內容call to OpenGL ES API with no current context (logged once per
    // thread)

    if (combineImage) {
      FrameBuffer fb = frameBuffer;
      GLBitmap =
          Bitmap.createBitmap(fb.getPixels(), fb.getWidth(), fb.getHeight(), Config.ARGB_8888);

      Bitmap combineBitmap;
      combineBitmap =
          Bitmap.createBitmap(GLBitmap.getWidth(), GLBitmap.getHeight(), Bitmap.Config.ARGB_8888);
      Canvas comboImage = new Canvas(combineBitmap);
      comboImage.drawBitmap(GLBitmap, 0f, 0f, null);
      comboImage.drawBitmap(Activity3Page.Activity3BitmapPaint, 0f, 0f, null);
      saveImage(combineBitmap);

      combineImage = false;
    }

    if (Activity3Page.currentEditStatus == EditStatus.Mode3D) {

      gl.glShadeModel(GL10.GL_SMOOTH);
      gl.glEnable(GL10.GL_DEPTH_TEST); // 啟動深度檢測(沒有看到的面就不會被畫)

      float deltaTime = (System.currentTimeMillis() - currentSystemTime) / 1000.0f;
      currentSystemTime = System.currentTimeMillis();
      if (colorValue >= 255) {
        colorValue = 255;
        colorChangeSpeed = -colorChangeSpeed;
      } else if (colorValue <= 0) {
        colorValue = 0;
        colorChangeSpeed = -colorChangeSpeed;
      }
      colorValue += (deltaTime * colorChangeSpeed);

      switch (Activity3Page.currentAction3DObject) {
        case DetectObject:
          SimpleVector ray =
              Interact2D.reproject2D3D(world.getCamera(), frameBuffer, (int) PointX, (int) PointY)
                  .normalize();
          Object[] res =
              world.calcMinDistanceAndObject3D(world.getCamera().getPosition(), ray, 1000);
          if (res[1] != null) {
            String name = null;
            name = ((Object3D) res[1]).getName();
            if (name == "Arch") {
              Activity3Page.currentAction3DObject = Action3DObject.Arch;
            } else if (name == "Box") {
              Activity3Page.currentAction3DObject = Action3DObject.Box;
            } else if (name == "Cylinder") {
              Activity3Page.currentAction3DObject = Action3DObject.Cylinder;
            }
          }
        case NoAction:
          arch.setAdditionalColor(new RGBColor(0, 0, 0, 0)); // 原色
          box.setAdditionalColor(new RGBColor(0, 0, 0, 0)); // 原色
          cylinder.setAdditionalColor(new RGBColor(0, 0, 0, 0)); // 原色
          break;
        case Arch:
          arch.setAdditionalColor(new RGBColor((int) colorValue, 0, 0, 255)); // 提示色
          box.setAdditionalColor(new RGBColor(0, 0, 0, 0)); // 原色
          cylinder.setAdditionalColor(new RGBColor(0, 0, 0, 0)); // 原色
          Handle3DControl(arch, archOriginPosition.z);
          break;

        case Box:
          arch.setAdditionalColor(new RGBColor(0, 0, 0, 0)); // 原色
          box.setAdditionalColor(new RGBColor((int) colorValue, 0, 0, 255)); // 提示色
          cylinder.setAdditionalColor(new RGBColor(0, 0, 0, 0)); // 原色
          Handle3DControl(box, boxOriginPosition.z);
          break;

        case Cylinder:
          arch.setAdditionalColor(new RGBColor(0, 0, 0, 0)); // 原色
          box.setAdditionalColor(new RGBColor(0, 0, 0, 0)); // 原色
          cylinder.setAdditionalColor(new RGBColor((int) colorValue, 0, 0, 255)); // 提示色
          Handle3DControl(cylinder, cylinderOriginPosition.z);
          break;
      }
    }
    frameBuffer.clear(backgroundColor);

    world.renderScene(frameBuffer);
    world.draw(frameBuffer);
    frameBuffer.display();
  }
  public void onSurfaceChanged(GL10 gl, int w, int h) {
    if (fb != null) {
      fb.dispose();
    }
    fb = new FrameBuffer(gl, w, h);

    Loader = new Model3D();

    if (master == null) {

      world = new World();
      world.setAmbientLight(20, 20, 20);

      sun = new Light(world);
      sun.setIntensity(250, 250, 250);

      // OBJECT 1
      try {
        double startTime1 = System.currentTimeMillis();
        obj1 = Loader.localloadModel("" + thingName1 + ".3ds", thingScale);
        double endTime1 = System.currentTimeMillis() - startTime1;

        Log.i("Object 1 loading time", endTime1 + "");
        dataEvent
            .getInstance()
            .getDatabaseManager()
            .saveData("Object 1 loading time", 0, endTime1, 0, 0);

      } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      obj1.build();
      world.addObject(obj1);

      Camera cam = world.getCamera();
      cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
      cam.lookAt(obj1.getTransformedCenter());

      SimpleVector sv = new SimpleVector();
      sv.set(obj1.getTransformedCenter());
      sv.y -= 100;
      sv.z -= 100;
      sun.setPosition(sv);
      MemoryHelper.compact();

      // OBJECT2
      try {
        double startTime2 = System.currentTimeMillis();
        obj2 = Loader.loadModel("" + thingName2 + ".3ds", thingScale);
        double endTime2 = System.currentTimeMillis() - startTime2;

        Log.i("Object 2 loading time", endTime2 + "");

        dataEvent
            .getInstance()
            .getDatabaseManager()
            .saveData("Object 2 loading time", 0, endTime2, 0, 0);

      } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }

      obj2.translate(-6, 28, 0);
      obj2.rotateY(-.6f);
      world.addObject(obj2);

      // OBJECT3
      try {

        double startTime3 = System.currentTimeMillis();
        obj3 = Loader.loadModel("" + thingName3 + ".3ds", thingScale);
        double endTime3 = System.currentTimeMillis() - startTime3;

        Log.i("Object 3 loading time", endTime3 + "");

        dataEvent
            .getInstance()
            .getDatabaseManager()
            .saveData("Object 3 loading time", 0, endTime3, 0, 0);

        boolean manualExtraction = true;
        if (manualExtraction == true) {
          extractDatabaseFile(new DatabaseCommons());
        }

      } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }

      obj3.translate(-15, -20, 0);
      obj3.rotateY(-.6f);
      world.addObject(obj3);

      /*if (master == null) {
          Logger.log("Saving master Activity!");
          master = MainActivity.this;
      }*/
    }
  }
 private void initCanvas() {
   canvas = new Canvas();
   canvas.setVisible(true);
   canvas = buffer.enableGLCanvasRenderer();
   this.add(canvas);
 }
 private void initBuffer() {
   buffer = new FrameBuffer(windowx, windowy, FrameBuffer.SAMPLINGMODE_HARDWARE_ONLY);
   buffer.optimizeBufferAccess();
   buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
   buffer.enableRenderer(IRenderer.RENDERER_OPENGL);
 }