/**
  * 法線を求める
  *
  * @param V 頂点配列
  * @param A 頂点の位置
  * @param B 頂点の位置
  * @param C 頂点の位置
  * @return 法線ベクトル
  */
 protected KGLPoint calcNormal(KGLPoint[] V, int A, int B, int C) {
   KGLPoint ret = null;
   KGLPoint BA = null;
   KGLPoint BC = null;
   // ベクトルB->A
   BA = KGLPoint.vector(V[B], V[A]);
   // ベクトルB->C
   BC = KGLPoint.vector(V[B], V[C]);
   // 法線の計算
   ret =
       KGLPoint.createXYZ(
           BA.Y() * BC.Z() - BA.Z() * BC.Y(),
           BA.Z() * BC.X() - BA.X() * BC.Z(),
           BA.X() * BC.Y() - BA.Y() * BC.X());
   ret.normalize(); // 正規化
   return ret;
 }
  /**
   * 描画用マテリアル情報をMQOデータから作成
   *
   * @param mqomat MQOファイルから読み込んだマテリアル情報
   * @param i_mqomat MQOファイルのマテリアル番号
   * @param mqoObjs MQOファイルのオブジェクト情報
   * @param vn 頂点法線配列
   * @return 描画用マテリアル情報
   */
  private GLMaterial makeMats(
      GL10 gl, material mqomat, int i_mqomat, objects mqoObjs, KGLPoint[] vn) {
    GLMaterial ret = new GLMaterial();
    ArrayList<KGLPoint> apv = new ArrayList<KGLPoint>();
    ArrayList<KGLPoint> apn = new ArrayList<KGLPoint>();
    ArrayList<KGLPoint> apuv = new ArrayList<KGLPoint>();
    ArrayList<KGLPoint> apc = new ArrayList<KGLPoint>();
    KGLPoint wpoint = null;
    boolean uvValid = false;
    boolean colValid = false;
    KGLPoint fn;
    float s;
    for (int f = 0; f < mqoObjs.face.length; f++) {
      if (mqoObjs.face[f].M == null) {
        continue;
      }
      if (mqoObjs.face[f].M != i_mqomat) continue;

      fn =
          calcNormal(
              mqoObjs.vertex, mqoObjs.face[f].V[0], mqoObjs.face[f].V[1], mqoObjs.face[f].V[2]);
      for (int v = 0; v < 3; v++) {
        apv.add(mqoObjs.vertex[mqoObjs.face[f].V[v]]);
        // apv.add(new KGLPoint(mqoObjs.vertex[mqoObjs.face[f].V[v]])) ;
        s =
            (float)
                Math.acos(
                    fn.X() * vn[mqoObjs.face[f].V[v]].X()
                        + fn.Y() * vn[mqoObjs.face[f].V[v]].Y()
                        + fn.Z() * vn[mqoObjs.face[f].V[v]].Z());
        if (mqoObjs.data.facet < s) {
          apn.add(fn);
        } else {
          apn.add(vn[mqoObjs.face[f].V[v]]);
        }
        wpoint = new KGLPoint(2);
        if (mqoObjs.face[f].UV == null) {
          wpoint.set_UV(0, 0);
        } else {
          wpoint.set_UV(mqoObjs.face[f].UV[v * 2 + 0], mqoObjs.face[f].UV[v * 2 + 1]);
          uvValid = true;
        }
        apuv.add(wpoint);
        wpoint = new KGLPoint(4);
        if (mqoObjs.face[f].COL == null) {
          if (mqomat.data.col == null) {
            wpoint.set_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
          } else {
            wpoint.set_COLOR(
                mqomat.data.col[0], mqomat.data.col[1], mqomat.data.col[2], mqomat.data.col[3]);
          }
        } else {
          wpoint.set_COLOR(
              mqoObjs.face[f].COL[v * 4 + 0],
              mqoObjs.face[f].COL[v * 4 + 1],
              mqoObjs.face[f].COL[v * 4 + 2],
              mqoObjs.face[f].COL[v * 4 + 3]);
          colValid = true;
        }
        apc.add(wpoint);
      }
    }
    ret.texID = texPool.getGLTexture(gl, mqomat.data.tex, mqomat.data.aplane, false);
    // @@@ reload 用
    if (ret.texID != 0) {
      ret.texName = mqomat.data.tex;
      ret.alphaTexName = mqomat.data.aplane;
    } else {
      ret.texName = null;
      ret.alphaTexName = null;
    }

    if (apv.size() == 0) return null;
    uvValid &= (ret.texID != 0);
    ret.name = mqomat.name;
    // uvValid = false ;
    KGLPoint[] wfv = null;
    KGLPoint[] wfn = null;
    KGLPoint[] wft = null;
    KGLPoint[] wfc = null;
    wfv = apv.toArray(new KGLPoint[0]);
    wfn = apn.toArray(new KGLPoint[0]);
    wft = apuv.toArray(new KGLPoint[0]);
    wfc = apc.toArray(new KGLPoint[0]);
    ret.vertex_num = wfv.length;

    // @@@ interleaveFormat は無いので分ける
    ret.uvValid = uvValid;
    ret.colValid = colValid;

    ret.vertexBuffer = ByteBuffer.allocateDirect(ret.vertex_num * 3 * 4);
    ret.vertexBuffer.order(ByteOrder.nativeOrder());
    ret.vertexBuffer.position(0);

    ret.normalBuffer = ByteBuffer.allocateDirect(ret.vertex_num * 3 * 4);
    ret.normalBuffer.order(ByteOrder.nativeOrder());
    ret.normalBuffer.position(0);

    if (uvValid) {
      ret.uvBuffer = ByteBuffer.allocateDirect(ret.vertex_num * 2 * 4);
      ret.uvBuffer.order(ByteOrder.nativeOrder());
      ret.uvBuffer.position(0);
    }
    if (colValid) {
      ret.colBuffer = ByteBuffer.allocateDirect(ret.vertex_num * 4 * 4);
      ret.colBuffer.order(ByteOrder.nativeOrder());
      ret.colBuffer.position(0);
    }

    // Log.i("KGLMetaseq", "vertex_num: "+ ret.vertex_num);

    for (int v = 0; v < ret.vertex_num; v++) {
      ret.vertexBuffer.putFloat(wfv[v].X());
      ret.vertexBuffer.putFloat(wfv[v].Y());
      ret.vertexBuffer.putFloat(wfv[v].Z());

      ret.normalBuffer.putFloat(wfn[v].X());
      ret.normalBuffer.putFloat(wfn[v].Y());
      ret.normalBuffer.putFloat(wfn[v].Z());

      if (uvValid) {
        ret.uvBuffer.putFloat(wft[v].U());
        ret.uvBuffer.putFloat(wft[v].V());
      }
      if (colValid) {
        ret.colBuffer.putFloat(wfc[v].R());
        ret.colBuffer.putFloat(wfc[v].G());
        ret.colBuffer.putFloat(wfc[v].B());
        ret.colBuffer.putFloat(wfc[v].A());
      }
    }
    if (mqomat.data.col != null) {
      ret.color = new float[mqomat.data.col.length];
      for (int c = 0; c < mqomat.data.col.length; c++) {
        ret.color[c] = mqomat.data.col[c];
      }
      if (mqomat.data.dif != null) {
        ret.dif = new float[mqomat.data.col.length];
        for (int c = 0; c < mqomat.data.col.length; c++) {
          ret.dif[c] = mqomat.data.dif * mqomat.data.col[c];
        }
        // KEICHECK difでアルファ値を1未満にすると透明度が変化する?
        ret.dif[3] = mqomat.data.col[3];
      }
      if (mqomat.data.amb != null) {
        ret.amb = new float[mqomat.data.col.length];
        for (int c = 0; c < mqomat.data.col.length; c++) {
          ret.amb[c] = mqomat.data.amb * mqomat.data.col[c];
        }
      }
      if (mqomat.data.emi != null) {
        ret.emi = new float[mqomat.data.col.length];
        for (int c = 0; c < mqomat.data.col.length; c++) {
          ret.emi[c] = mqomat.data.emi * mqomat.data.col[c];
        }
      }
      if (mqomat.data.spc != null) {
        ret.spc = new float[mqomat.data.col.length];
        for (int c = 0; c < mqomat.data.col.length; c++) {
          ret.spc[c] = mqomat.data.spc * mqomat.data.col[c];
        }
      }
    }
    if (mqomat.data.pow != null) {
      ret.power = new float[1];
      ret.power[0] = mqomat.data.pow;
    }
    ret.shadeMode_IsSmooth = true; // defaultはtrue
    if (mqoObjs.data.shading == 0) ret.shadeMode_IsSmooth = false;

    return ret;
  }