/** * vertexチャンクの読み込み * * @param num チャンクにあるデータ数 * @param br 読み込みストリーム * @param scale モデルの倍率 * @return 頂点配列 * @throws Exception */ private KGLPoint[] readVertex(int num, multiInput br, float scale) throws Exception { KGLPoint[] ret = null; String line = null; String[] s; int cnt; ret = new KGLPoint[num]; cnt = 0; try { while ((line = br.readLine()) != null) { if (line.length() <= 0) continue; line = line.trim(); if (line.equals("}")) break; s = line.split(" ", 3); ret[cnt] = KGLPoint.createXYZ( Float.parseFloat(s[0]) * scale, Float.parseFloat(s[1]) * scale, Float.parseFloat(s[2]) * scale); cnt++; } } catch (Exception e) { Log.e("KGLMetaseq", "MQOファイル フォーマットエラー(Object>vertex)[" + line + "]"); throw e; } if (cnt != num) return null; return ret; }
/** * BVertexチャンクの読み込み * * @param br 読み込みストリーム * @return 頂点配列 * @param scale モデルの倍率 * @throws Exception */ private KGLPoint[] readBvertex(multiInput br, float scale) throws Exception { KGLPoint[] ret = null; String line = null; String[] s; int p; int pe; int datasize = 0; try { while ((line = br.readLine().trim()) != null) { if (line.length() <= 0) continue; s = line.split(" "); if (s[0].equals("Vector")) { if (s.length != 3) { line = null; break; } p = s[2].indexOf("["); pe = s[2].indexOf("]"); datasize = Integer.parseInt(s[2].substring(p + 1, pe)); break; } } } catch (Exception e) { Log.e("KGLMetaseq", "MQOファイル フォーマットエラー(Object>Bvertex)[" + line + "]"); throw new KGLException(e); } if (line == null) { return null; } if (datasize == 0) return null; byte[] bbuf = new byte[datasize]; if (datasize != br.read(bbuf)) return null; ByteBuffer bb; bb = ByteBuffer.wrap(bbuf); bb.order(ByteOrder.LITTLE_ENDIAN); // MQOファイルのエンディアンはIntel形式 FloatBuffer fb = bb.asFloatBuffer(); ret = new KGLPoint[fb.limit() / 3]; fb.position(0); float[] wf = new float[3]; for (int i = 0; i < ret.length; i++) { fb.get(wf); ret[i] = KGLPoint.create(wf).scale(scale); } while ((line = br.readLine().trim()) != null) { if (line.equals("}")) break; } return ret; }
/** * 頂点法線を求める * * @param mqoObj 読み込んだMQOデータ * @return 頂点法線 */ protected KGLPoint[] vNormal(objects mqoObj) { KGLPoint[] ret = null; KGLPoint sn = null; // 頂点に接している面の法線を頂点法線に足し込んでいく ret = new KGLPoint[mqoObj.vertex.length]; for (int f = 0; f < mqoObj.face.length; f++) { sn = calcNormal(mqoObj.vertex, mqoObj.face[f].V[0], mqoObj.face[f].V[1], mqoObj.face[f].V[2]); if (sn == null) continue; for (int i = 0; i < 3; i++) { if (ret[mqoObj.face[f].V[i]] == null) { ret[mqoObj.face[f].V[i]] = KGLPoint.createXYZ(0, 0, 0); } ret[mqoObj.face[f].V[i]].add(sn); } } // 正規化(長さを求めて、ソレで割って0~1の値にする!) for (int v = 0; v < ret.length; v++) { if (ret[v] == null) continue; ret[v].normalize(); } return ret; }
/** * 法線を求める * * @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; }