import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.io.File; import java.io.IOException; import java.nio.DoubleBuffer; import java.util.ArrayList; import java.util.List; import javax.media.opengl.GL; import javax.media.opengl.GL2; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLEventListener; import javax.media.opengl.GLProfile; import javax.media.opengl.awt.GLCanvas; import javax.media.opengl.glu.GLU; import javax.media.opengl.glu.GLUtessellator; import javax.media.opengl.glu.GLUtessellatorCallback; import javax.swing.JFrame; import tangram.GeomPoint; import tangram.PieceInfo; import tangram.Tangram; import tangram.svcs.Listios; import com.sun.opengl.util.Animator; import com.sun.opengl.util.BufferUtil; import com.sun.opengl.util.texture.Texture; import com.sun.opengl.util.texture.TextureIO; public class editerlooks extends JFrame implements GLEventListener, MouseListener, MouseMotionListener { static GLCanvas canvas; static Animator animator; static GLU glu; static Texture[] texture; // テクスチャのバリエーション static DoubleBuffer vertices; // 頂点座標バッファ static DoubleBuffer normals; // 法線バッファ static DoubleBuffer texcoord; // テクスチャ座標バッファ List grefarn; // 1ピースの表・裏・側面の、typidxn内オフセットとポリゴン数 List typidxn; // 1ポリゴンの描画モード・バッファ内オフセット・座標数 Tangram tan; // jteのタングラムクラス Listios lios; // jteのリストIO int silno = 1; // シルエットNo. String jteres = "res/cocoon.jte"; // 読み込むjteファイル名 int[] tex; // 各ピースのテクスチャ double zoom = 1./160; // ノーマライズ因子 double hzw = 10; // ノーマライズ前のピース高さ/2 boolean drawsw_front = true; // ピース表面の描画 boolean drawsw_back = true; // ピース裏面の描画 boolean drawsw_side = true; // ピース側面の描画 boolean texenblObj = true; boolean texenblFloor = false; enum DayTime { MORNING, EVENING }; DayTime daytime = DayTime.MORNING; double T = .0; // アニメーション用タイマー double camz = -2.5;//-9; /* * コンストラクタ */ public editerlooks() { glu = new GLU(); canvas = new GLCanvas(new GLCapabilities(GLProfile.getDefault())); canvas.addGLEventListener(this); canvas.addMouseListener(this); canvas.addMouseMotionListener(this); getContentPane().add(canvas); } public void run() { setSize(320+10, 460+30); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); canvas.requestFocusInWindow(); animator = new Animator(canvas); animator.setRunAsFastAsPossible(false); animator.start(); } public static void main(String[] args) { new editerlooks().run(); } public void init(GLAutoDrawable drawable) { // テクスチャ読み込み texture = new Texture[6]; try { texture[0] = TextureIO.newTexture(new File("res/284.png"), true); texture[1] = TextureIO.newTexture(new File("res/wood_texture.png"), true); texture[2] = TextureIO.newTexture(new File("res/Cherry_Wood_Texture_by_kttyjay.png"), true); texture[3] = TextureIO.newTexture(new File("res/f0178135_10523169.png"), true); texture[4] = TextureIO.newTexture(new File("res/fs1205-sc.png"), true); texture[5] = TextureIO.newTexture(new File("res/sykamor_color.png"), true); } catch (IOException ex) { ex.printStackTrace(); } // jte読み込み tan = new Tangram(); lios = new Listios(); lios.loadXML(tan, jteres, false, false); // テクスチャ指定 tex = new int[tan.pinfo.num]; for (int i = 0; i < tan.pinfo.num; i++) tex[i] = i%5; // バッファ準備 GL2 gl = drawable.getGL().getGL2(); setupPointers(gl); gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); gl.glEnableClientState(GL2.GL_NORMAL_ARRAY); gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY); gl.glVertexPointer(3, GL2.GL_DOUBLE, 0, vertices); gl.glNormalPointer(GL2.GL_DOUBLE, 0, normals); gl.glTexCoordPointer(2, GL2.GL_DOUBLE, 0, texcoord); } public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { GL2 gl = drawable.getGL().getGL2(); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(60, (float)width/(float)height, 0.5, 50.0) ; // ↑ ↑ ↑ ↑ // 視野角[deg] アスペクト比 最近点 最遠い点 gl.glViewport( 0, 0, width , height ); // ↑ ↑ ↑ ↑ // 左下pxl座標X Y ウィンドウ幅 高さ gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); } public void display(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); if ((T += 0.037) > 360.0 ) T -= 360.0; //オブジェクト描画モードにする。 gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); gl.glClearColor(.0f, .0f, .0f, 1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT); gl.glClearDepth(1.0f); gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(GL.GL_LEQUAL); gl.glClearStencil(0); gl.glCullFace(GL2.GL_BACK); gl.glEnable(GL.GL_CULL_FACE); /*// フォグ設定 float[] fogcolor = new float[]{ 1f, 1f, 1f, 1 }; gl.glDisable(GL2.GL_FOG); gl.glFogi(GL2.GL_FOG_MODE, GL2.GL_EXP); gl.glFogf(GL2.GL_FOG_DENSITY, 0.05f); gl.glFogfv(GL2.GL_FOG_COLOR, fogcolor, 0); */ // カメラ glu.gluLookAt( 0, 0, (float)camz, // 視点の位置x,y,z, 0, 0, 0, // 視界の中心位置の参照点座標x,y,z 0,-1, 0); // 視界の上方向のベクトルx,y,z // 照明 float[][] lightpos = new float[2][4]; float[] LSPECULAR = new float[4]; float[] LDIFFUSE = new float[4]; float[] LAMBIENT = new float[4]; switch (daytime) { case MORNING: lightpos = new float[][]{ { -0.5f, -1.5f, -3f, 1 }, { 0.75f, 0.75f, -1f, 1 } }; LSPECULAR = new float[]{1f, 1f, 1f, 1f}; LDIFFUSE = new float[]{.1f, .1f, .2f, 1f}; LAMBIENT = new float[]{.3f, .3f, .4f, 1f}; break; case EVENING: lightpos = new float[][]{ { -0.25f, -0.75f, -2f, 1 }, { 0.75f, 1.75f, -1f, 1 } }; LSPECULAR = new float[]{1f, 1f, 1f, 1f}; LDIFFUSE = new float[]{.1f, .1f, .2f, 1f}; LAMBIENT = new float[]{.2f, .2f, .3f, 1f}; break; } gl.glEnable(GL2.GL_LIGHTING); gl.glEnable(GL2.GL_LIGHT0); gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, lightpos[0], 0); gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, LSPECULAR, 0); gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, LDIFFUSE, 0); gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, LAMBIENT, 0); gl.glEnable(GL2.GL_LIGHT1); gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, lightpos[1], 0); gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPECULAR, LSPECULAR, 0); gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_DIFFUSE, LDIFFUSE, 0); gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_AMBIENT, LAMBIENT, 0); // 座標系を保存 gl.glPushMatrix(); //オブジェクトの描画 float[] MSPECULAR = new float[4]; float[] MDIFFUSE = new float[4]; float[] MAMBIENT = new float[4]; float MSHININESS = 0f; switch (daytime) { case MORNING: MSPECULAR = new float[]{1.f, 1.f, 1.f, 1f}; MDIFFUSE = new float[]{.5f, .5f, 1.f, 1f}; MAMBIENT = new float[]{.8f, .8f, .9f, 1f}; MSHININESS = 10f; break; case EVENING: MSPECULAR = new float[]{1.f, 1.f, 1.f, 1f}; MDIFFUSE = new float[]{.94f, .93f, .2f, 1f}; MAMBIENT = new float[]{.75f, .7f, .65f, 1f}; MSHININESS = 100f; break; } gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, MSPECULAR, 0); gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, MDIFFUSE, 0); gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_AMBIENT, MAMBIENT, 0); gl.glMaterialf(GL.GL_FRONT_AND_BACK, GL2.GL_SHININESS, MSHININESS); drawObj(gl, texenblObj); // 背景描画 float[] MSPECULAR2 = new float[4]; float[] MDIFFUSE2 = new float[4]; float[] MAMBIENT2 = new float[4]; float MSHININESS2 = 0f; switch (daytime) { case MORNING: MSPECULAR2 = new float[]{1.f, 1.f, 1.f, 1f}; MDIFFUSE2 = new float[]{.7f, .7f, 1.f, .2f}; MAMBIENT2 = new float[]{1.f, 1.f, 1.f, 1f}; MSHININESS2 = 100.0f; break; case EVENING: MSPECULAR2 = new float[]{1.f, 1.f, 1.f, 1f}; MDIFFUSE2 = new float[]{.1f, .1f, .2f, .4f}; MAMBIENT2 = new float[]{.2f, .15f, .1f, 1f}; MSHININESS2 = 100.0f; break; } gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, MSPECULAR2, 0); gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, MDIFFUSE2, 0); gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_AMBIENT, MAMBIENT2, 0); gl.glMaterialf(GL.GL_FRONT_AND_BACK, GL2.GL_SHININESS, MSHININESS2); drawFloor(gl, texenblFloor); // 保存した座標系に戻す gl.glPopMatrix(); ///////////////////////////////////// float[] pM = new float[16]; final float[] floor_planar = new float[] {0, 0, -1, 0}; for (int n = 0; n < 2; n++) { // 今の座標系を保存しておく gl.glPushMatrix(); // 平面射影行列の算出 shadowMatrix(pM, floor_planar, lightpos[n]); gl.glEnable(GL2.GL_LIGHTING); if (n == 0) { gl.glEnable(GL2.GL_LIGHT0); gl.glDisable(GL2.GL_LIGHT1); gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, lightpos[0], 0); } else { gl.glDisable(GL2.GL_LIGHT0); gl.glEnable(GL2.GL_LIGHT1); gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, lightpos[1], 0); } //床のステンシルを付ける gl.glEnable(GL.GL_STENCIL_TEST); gl.glStencilFunc(GL.GL_ALWAYS, 1, ~0); //これから描画するもののステンシル値にすべて1タグをつける gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP ,GL.GL_REPLACE); //カラー・デプスバッファマスクをセットする //これで以下の内容のピクセルの色の値は、書き込まれない。 gl.glColorMask(false, false, false, false); gl.glDepthMask(false); //床の描画 drawFloor(gl, texenblObj); //床にオブジェクトの影のステンシルを付ける gl.glEnable(GL2.GL_STENCIL_TEST); gl.glStencilFunc(GL.GL_EQUAL, 1, ~0); //これから描画するもののステンシル値にすべて1タグをつける gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP ,GL.GL_INCR); gl.glDisable(GL.GL_DEPTH_TEST); gl.glDisable(GL.GL_CULL_FACE); gl.glPushMatrix(); gl.glMultMatrixf(pM, 0); drawObj(gl, texenblObj); gl.glPopMatrix(); gl.glEnable(GL.GL_DEPTH_TEST); gl.glEnable(GL.GL_CULL_FACE); //ビットマスクを解除 gl.glColorMask(true, true, true, true); gl.glDepthMask(true); //影をつける gl.glStencilFunc(GL.GL_EQUAL, 2, ~0 ); gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glColor4f(0.0f, 0.0f, 0.0f, 0.1f); gl.glDisable(GL.GL_DEPTH_TEST); drawFloor(gl, texenblFloor); gl.glEnable(GL.GL_DEPTH_TEST); gl.glDisable(GL.GL_BLEND); gl.glDisable(GL.GL_STENCIL_TEST); // 座標系を戻す gl.glPopMatrix(); } ///////////////////////////////////// // コマンドのフラッシュ gl.glFlush(); } /* * Create a matrix that will project the desired shadow. */ private void shadowMatrix( float m[], // 作成する行列のポインタ float plane[], // 射影する表面の平面方程式の係数 float light[]) // 光源の同時座標値 { float dot; // Find dot product between light position vector and ground plane normal. dot = plane[0] * light[0] + plane[1] * light[1] + plane[2] * light[2] + plane[3] * light[3]; m[0] = dot - light[0] * plane[0]; m[4] = 0.f - light[0] * plane[1]; m[8] = 0.f - light[0] * plane[2]; m[12] = 0.f - light[0] * plane[3]; m[1] = 0.f - light[1] * plane[0]; m[5] = dot - light[1] * plane[1]; m[9] = 0.f - light[1] * plane[2]; m[13] = 0.f - light[1] * plane[3]; m[2] = 0.f - light[2] * plane[0]; m[6] = 0.f - light[2] * plane[1]; m[10] = dot - light[2] * plane[2]; m[14] = 0.f - light[2] * plane[3]; m[3] = 0.f - light[3] * plane[0]; m[7] = 0.f - light[3] * plane[1]; m[11] = 0.f - light[3] * plane[2]; m[15] = dot - light[3] * plane[3]; } /* * 背景描画 */ private void drawFloor(GL2 gl, boolean texenbl) { if (texenbl) { gl.glEnable(GL.GL_TEXTURE_2D); texture[5].enable(); texture[5].bind(); } for (int x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { gl.glPushMatrix(); // 座標を保存 gl.glTranslated((double)x*4., (double)y*4., 0.5); gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); gl.glPopMatrix(); // 座標を元に戻す } } if (texenbl) { texture[5].disable(); gl.glDisable(GL.GL_TEXTURE_2D); } } /* * オブジェクト描画 */ private void drawObj(GL2 gl, boolean texenbl) { int tmpno; int gei, ref, arn; PieceInfo pi; for (int i = 0; i < tan.pinfo.num; i++) { tmpno = silno; if (texenbl) { gl.glEnable(GL.GL_TEXTURE_2D); texture[tex[i]].enable(); texture[tex[i]].bind(); } for (int x = -0; x <= 0; x++) { for (int y = -0; y <= 0; y++) { pi = lios.get(tmpno); tmpno++; if (tmpno == lios.getCount()) tmpno = 0; gl.glPushMatrix(); // 座標を保存 gl.glTranslated((double)x*2.7, (double)y*2.7, 0); //gl.glRotated(T + tmpno*20, 0, 1, 0); gl.glTranslated(pi.x[i]*zoom, pi.y[i]*zoom, 0); // ピース位置へ移動 gl.glRotated(pi.rad[i]*180/Math.PI, 0, 0, 1); // 回転 gl.glRotated((1-pi.flip[i])*90, 0, 1, 0); // 反転 // ピースのIDからピース形状No.を決める for (gei = 0; gei < tan.geombank.geombank.size(); gei++) { if (pi.id[i].equals(tan.geombank.geombank.get(gei).id)) break; } // ピースの重心にスライド gl.glTranslated(-tan.geombank.geombank.get(gei).local_ox*zoom, -tan.geombank.geombank.get(gei).local_oy*zoom, 0); // ピース表面の描画 if (drawsw_front) { ref = grefarn.get(gei*6+0); arn = grefarn.get(gei*6+1); for (int j = 0; j < arn; j++, ref += 3) { gl.glDrawArrays(typidxn.get(ref), typidxn.get(ref+1), typidxn.get(ref+2)); } } // ピース裏面の描画 if (drawsw_back) { ref = grefarn.get(gei*6+2); arn = grefarn.get(gei*6+3); for (int j = 0; j < arn; j++, ref += 3) { gl.glDrawArrays(typidxn.get(ref), typidxn.get(ref+1), typidxn.get(ref+2)); } } // ピース側面の描画 if (drawsw_side) { ref = grefarn.get(gei*6+4); arn = grefarn.get(gei*6+5); for (int j = 0; j < arn; j++, ref += 3) { gl.glDrawArrays(typidxn.get(ref), typidxn.get(ref+1), typidxn.get(ref+2)); } } gl.glPopMatrix(); // 座標を元に戻す } } if (texenbl) { texture[tex[i]].disable(); gl.glDisable(GL.GL_TEXTURE_2D); } } } /* * 描画データの作成 */ private void setupPointers(GL2 gl) { int i, j; int idx = 0; int pnorg, pn; double x0, y0; double x1, y1; double dx, dy; double l; double dx0, dy0; double dx1, dy1; double tdx = 0, tdy = 0; double tdxofst, tdyofst; double[] ix, iy; boolean[] imid; List gp; boolean etgl; boolean ldsc = false; // インデックスの新規作成 grefarn = new ArrayList(10); typidxn = new ArrayList(20); // テセレータ準備 GLUtessellator tobj = GLU.gluNewTess(); tessellCallBack tessCallback = new tessellCallBack(gl, glu); GLU.gluTessCallback(tobj, GLU.GLU_TESS_VERTEX, tessCallback); GLU.gluTessCallback(tobj, GLU.GLU_TESS_BEGIN, tessCallback); GLU.gluTessCallback(tobj, GLU.GLU_TESS_END, tessCallback); GLU.gluTessCallback(tobj, GLU.GLU_TESS_COMBINE, tessCallback); GLU.gluTessCallback(tobj, GLU.GLU_TESS_ERROR, tessCallback); for (boolean lap = false, writermode = false; !lap; lap = !((writermode = !writermode) ^ lap)) { idx = 0; tessCallback.setup(writermode); // 正方形パネル final double sz = 2; if (writermode) { vertices.put(-sz);vertices.put(-sz);vertices.put(0.); vertices.put(-sz);vertices.put( sz);vertices.put(0.); vertices.put( sz);vertices.put(-sz);vertices.put(0.); vertices.put( sz);vertices.put( sz);vertices.put(0.); texcoord.put(0.);texcoord.put(0.); texcoord.put(0.);texcoord.put(1.); texcoord.put(1.);texcoord.put(0.); texcoord.put(1.);texcoord.put(1.); normals.put(0.);normals.put(0.);normals.put(-1.); normals.put(0.);normals.put(0.);normals.put(-1.); normals.put(0.);normals.put(0.);normals.put(-1.); normals.put(0.);normals.put(0.);normals.put(-1.); } idx += 4; tessCallback.idx = idx; // 各ピースの描画(形状)データ作成 for (int gei = 0; gei < tan.geombank.geombank.size(); gei++) { gp = tan.geombank.geombank.get(gei).geompoints; pnorg = gp.size(); // 始点と終点が同じなら、頂点数-1 if ((gp.get(0).x[0] == gp.get(pnorg-1).x[0]) && (gp.get(0).y[0] == gp.get(pnorg-1).y[0])) pnorg--; // 実頂点の数仮決定 pn = pnorg; for (i = 0; i < pnorg; i++) { if (gp.get(i).kind == GeomPoint.PATH_CURVETO) pn += 9; } // 実頂点座標の作成 ix = new double[pn]; iy = new double[pn]; imid = new boolean[pn]; for (i = 0, j = 0; i < pnorg; i++) { switch(gp.get(i).kind) { case GeomPoint.PATH_MOVETO: case GeomPoint.PATH_LINETO: ix[j] = gp.get(i).x[0]; iy[j] = gp.get(i).y[0]; imid[j] = false; j++; break; case GeomPoint.PATH_CURVETO: // 3次ベジェ曲線は線分に分割 for (int cnt = 1; cnt <= 10; cnt++) { double t = (double)cnt/10.0; double s = 1 - t; ix[j+cnt-1] = ix[j-1] * s*s*s + gp.get(i).x[0] * 3*s*s*t + gp.get(i).x[1] * 3*s*t*t + gp.get(i).x[2] * t*t*t; iy[j+cnt-1] = iy[j-1] * s*s*s + gp.get(i).y[0] * 3*s*s*t + gp.get(i).y[1] * 3*s*t*t + gp.get(i).y[2] * t*t*t; imid[j+cnt-1] = (cnt > 0 && cnt < 10); } j += 10; break; } } // 実頂点の始点と終点が同じなら、実頂点数-1 if (ix[0] == ix[pn-1] && iy[0] == iy[pn-1]) pn--; // 頂点の順序逆転判定 double tmp = iy[0]; for (i = 1, j = 0; i < pn; i++) { if (iy[i] <= tmp) { // y座標最小の点を探す tmp = iy[i]; j = i; } } i = j; // iがy座標最小 for (dx0 = dy0 = 0, j = 0; j < pn; j++) { // 前方の差分 dx0 = ix[i] - ix[(i+pn-j)%pn]; dy0 = iy[i] - iy[(i+pn-j)%pn]; if (dx0 != 0. || dy0 != 0.) break; } for (dx1 = dy1 = 0, j = 0; j < pn; j++) { // 後方の差分 dx1 = ix[(i+j)%pn] - ix[i]; dy1 = iy[(i+j)%pn] - iy[i]; if (dx1 != 0. || dy1 != 0.) break; } tmp = dx1*dy0 - dx0*dy1; // 外積 /* System.out.println(tan.geombank.geombank.get(gei).id); System.out.println("product = " + tmp); System.out.println("pn = " + pn); System.out.println("i = " + i); System.out.println("i-3[" + (i+pn-3)%pn + "]:(" + ix[(i+pn-3)%pn] + ", " + iy[(i+pn-3)%pn] + ")"); System.out.println("i-2[" + (i+pn-2)%pn + "]:(" + ix[(i+pn-2)%pn] + ", " + iy[(i+pn-2)%pn] + ")"); System.out.println("i-1[" + (i+pn-1)%pn + "]:(" + ix[(i+pn-1)%pn] + ", " + iy[(i+pn-1)%pn] + ")"); System.out.println("i [" + i + "]:(" + ix[i] + ", " + iy[i] + ")"); System.out.println("i+1[" + (i+1)%pn + "]:(" + ix[(i+1)%pn] + ", " + iy[(i+1)%pn] + ")"); System.out.println("i+2[" + (i+2)%pn + "]:(" + ix[(i+2)%pn] + ", " + iy[(i+2)%pn] + ")"); System.out.println("i+3[" + (i+3)%pn + "]:(" + ix[(i+3)%pn] + ", " + iy[(i+3)%pn] + ")"); System.out.println("d0 = (" + dx0 + ", " + dy0 + ")"); System.out.println("d1 = (" + dx1 + ", " + dy1 + ")"); System.out.println("- - -"); */ // 実頂点の順序逆転 boolean tmpf; if (tmp < 0) { for (i = 0; i < pn/2; i++) { j = pn-1-i; tmp = ix[i]; ix[i] = ix[j]; ix[j] = tmp; tmp = iy[i]; iy[i] = iy[j]; iy[j] = tmp; tmpf = imid[i]; imid[i] = imid[j]; imid[j] = tmpf; } } // ピース表面のデータ作成 tessCallback.tcnt = 0; if (writermode) grefarn.add(typidxn.size()); GLU.gluTessBeginPolygon(tobj, null); GLU.gluTessBeginContour(tobj); for (i = 0; i < pn; i++) { GLU.gluTessVertex(tobj, new double[] {ix[i]*zoom, iy[i]*zoom, -hzw*zoom}, 0, new double[] {ix[i]*zoom, iy[i]*zoom, -hzw*zoom}); } GLU.gluTessEndContour(tobj); GLU.gluTessEndPolygon(tobj); if (writermode) grefarn.add(tessCallback.tcnt); idx = tessCallback.idx; // ピース裏面のデータ作成 tessCallback.tcnt = 0; if (writermode) grefarn.add(typidxn.size()); GLU.gluTessBeginPolygon(tobj, null); GLU.gluTessBeginContour(tobj); for (i = pn-1; i >= 0; i--) { GLU.gluTessVertex(tobj, new double[] {ix[i]*zoom, iy[i]*zoom, hzw*zoom}, 0, new double[] {ix[i]*zoom, iy[i]*zoom, hzw*zoom}); } GLU.gluTessEndContour(tobj); GLU.gluTessEndPolygon(tobj); if (writermode) grefarn.add(tessCallback.tcnt); idx = tessCallback.idx; // ピース側面のデータ作成 if (writermode) grefarn.add(typidxn.size()); if (writermode) grefarn.add(pn); for (i = 0; i < pn; i++) { x0 = ix[i]; y0 = iy[i]; x1 = ix[(i + 1) % pn]; y1 = iy[(i + 1) % pn]; dx = x1 - x0; dy = y1 - y0; l = Math.sqrt(dx*dx + dy*dy); // テクスチャ座標計算 if (imid[i]) { // 曲線補間点なら前回座標を引き継ぎ tdxofst = (ldsc) ? tdx : 0; tdyofst = (ldsc) ? 0 : tdy; } else { // 曲線補間点でなければldsc更新、切り出し座標の初期化 ldsc = (Math.abs(dx) > Math.abs(dy)); tdxofst = tdyofst = 0; } tdx = tdxofst + ((ldsc) ? l : hzw*2); tdy = tdyofst + ((ldsc) ? hzw*2 : l); if (tdx*zoom > 1 || tdy*zoom > 1) { // テクスチャ画像から出てしまったら戻す tdx -= tdxofst; tdy -= tdxofst; tdxofst = tdyofst = 0; } // 頂点(i)の接線計算 if (imid[i]) { dx = x1 - ix[(i + pn - 1) % pn]; dy = y1 - iy[(i + pn - 1) % pn]; l = Math.sqrt(dx*dx + dy*dy); } dx0 = dx/l; dy0 = dy/l; // 頂点(i+1)の接線計算 if (imid[(i + 1) % pn]) { dx = ix[(i + 2) % pn] - x0; dy = iy[(i + 2) % pn] - y0; l = Math.sqrt(dx*dx + dy*dy); } dx1 = dx/l; dy1 = dy/l; // 座標をセット if (writermode) typidxn.add(GL.GL_TRIANGLE_STRIP); if (writermode) typidxn.add(idx); if (writermode) typidxn.add(4); for (j = 0, etgl = true; j < 4; j++, etgl = !etgl, idx++) { if (writermode) { vertices.put((etgl ? x0 : x1)*zoom); vertices.put((etgl ? y0 : y1)*zoom); vertices.put(((j < 2) ? hzw : -hzw)*zoom); texcoord.put(((etgl) ? ((ldsc) ? tdxofst : ((j < 2) ? tdxofst : tdx)) : ((ldsc) ? tdx : ((j < 2) ? tdxofst : tdx)))*zoom); texcoord.put(((etgl) ? ((ldsc) ? ((j < 2) ? tdyofst : tdy) : tdyofst) : ((ldsc) ? ((j < 2) ? tdyofst : tdy) : tdy ))*zoom); normals.put(etgl ? -dy0 : -dy1); normals.put(etgl ? dx0 : dx1); normals.put(0.); } } } tessCallback.idx = idx; } // バッファ作成 if (!writermode) { vertices = BufferUtil.newDoubleBuffer(idx*3); texcoord = BufferUtil.newDoubleBuffer(idx*2); normals = BufferUtil.newDoubleBuffer(idx*3); } System.out.println(writermode); } // テセレータ消去 GLU.gluDeleteTess(tobj); // バッファのリワインド vertices.rewind(); texcoord.rewind(); normals.rewind(); // 確認用出力 /* for (Iterator it = grefarn.iterator(); it.hasNext(); ) System.out.println(it.next() + ", " + it.next()); for (Iterator it = typidxn.iterator(); it.hasNext(); ) System.out.println(it.next() + ", " + it.next() + ", " + it.next()); */ System.out.println(tan.getPuzzleName()); System.out.println((silno+1) + ". " + lios.get(silno).name); } /* * テセレータコールバック */ private class tessellCallBack implements GLUtessellatorCallback { public int idx = 0; public int tcnt = 0; public boolean writermode = false; private GLU glu; private int start; final String[] types = new String[] { "0:POINTS", "1:LINES", "2:LINE_LOOP", "3:LINE_STRIP", "4:TRIANGLES", "5:TRIANGLE_STRIP", "6:TRIANGLE_FAN", "7:", "8:", "9:POLYGON" }; public tessellCallBack(GL2 gl, GLU glu) { this.glu = glu; } public void setup(boolean writermode) { idx = 0; tcnt = 0; this.writermode = writermode; } // テセレーションの結果、発行される形状定義関連コマンドのコールバックを設定できる // ここでは、glBeginやglEndなどのタイミングを利用して、テセレーションの結果をバッファに蓄積する public void begin(int type) { start = idx; if (writermode) { typidxn.add(type); typidxn.add(start); } //System.out.println("- - begin " + types[type]); } public void end() { tcnt++; if (writermode) { typidxn.add(idx - start); } //System.out.println("- - end " + start + ", " + (idx - start)); } public void vertex(Object vertexData) { double[] pointer; if (vertexData instanceof double[]) { pointer = (double[]) vertexData; if (writermode) { vertices.put(pointer[0]); vertices.put(pointer[1]); vertices.put(pointer[2]); texcoord.put(pointer[0]); texcoord.put(pointer[1]); normals.put(.0); normals.put(.0); normals.put(pointer[2] > .0 ? 1. : -1.); } idx++; //System.out.println("v " + pointer[0]+", "+pointer[1]+", "+pointer[2]); } } public void edgeFlag(boolean boundaryEdge) {} public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) { double[] vertex = new double[3]; vertex[0] = coords[0]; vertex[1] = coords[1]; vertex[2] = coords[2]; outData[0] = vertex; } public void error(int errnum) { String estring; estring = glu.gluErrorString(errnum); System.err.println("Tessellation Error: " + estring); System.exit(0); } public void beginData(int type, Object polygonData) {} public void endData(Object polygonData) {} public void vertexData(Object vertexData, Object polygonData) {} public void edgeFlagData(boolean boundaryEdge, Object polygonData) {} public void combineData(double[] coords, Object[] data, float[] weight, Object[] outData, Object polygonData) {} public void errorData(int errnum, Object polygonData) {} } /* * その他 */ public void dispose(GLAutoDrawable drawable){} public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {} int prey; public void mouseClicked(MouseEvent mouse){} public void mouseEntered(MouseEvent mouse){} public void mouseExited(MouseEvent mouse){} public void mouseReleased(MouseEvent mouse){} public void mousePressed(MouseEvent e) { prey = e.getY(); T = 0; if (e.getButton() == MouseEvent.BUTTON1) { if (silno+1 == lios.getCount()) { silno = 0; } else { silno++; } } else { if (silno == 0) { silno = lios.getCount() - 1; } else { silno--; if (daytime == DayTime.MORNING) daytime = DayTime.EVENING; else if (daytime == DayTime.EVENING) daytime = DayTime.MORNING; } } System.out.println((silno+1) + ". " + lios.get(silno).name); System.out.println("cam z=" + camz); } public void mouseMoved(MouseEvent mouse){} public void mouseDragged(MouseEvent e) { int y = e.getY(); //camz += (double)(y - prey)*zoom; prey = y; } }