import ddf.minim.signals.*; import ddf.minim.*; import ddf.minim.analysis.*; import ddf.minim.effects.*; /* mqoview for processing sample code. Swinging leak by Hatyune Type 1-1 2009.2.5 reco */ import javax.media.opengl.*; import processing.opengl.*; // 下記の2つのライブラリのインポートが必要 import jp.nyatla.kGLModel.*; import jp.nyatla.kGLModel.contentprovider.*; // KGLModelData[] model_data = new KGLModelData[100]; //モデルデータ格納用 ContentProvider content_provider; //読み込みファイル・URL格納 PFont font; PFont font2; float a; // 回転数を保持(デモ用) int play_frame=0; int n_anim = 24; //アニメーション枚数 float anim_per_frame = 1; //1枚のアニメを表示するフレーム数 frame_rate / anim_per_frame = 秒毎のコマ数 boolean load_model = false; // ロードフラグ(ロード完了で1を返す) int play_anim_no; int anim_count=0; int auto_mode = 0; int n_manual_swing=0; int n_total_manual_swing=0; int t1=0,t2=0; float anim_speed = 100; int f_animation; //アニメーション中華を判断する int camera_angle = 1; //カメラアングルを決定します float hatyune_rotate_speed = 0; // 回転スピードです。(単位ラジアンです)フレーム毎にこの値が加算されます Minim minim; AudioPlayer player; int playhead = 0; void setup() { size(800, 600, OPENGL); frameRate(24); background(128); // colorMode(RGB, 100); font=createFont("FFScala", 12); // font2 = loadFont("VL-PGothic-Regular-16.vlw"); String[] lines = loadStrings("http://cgi.hyde-ysd.com/reco-memo/Proce55ing/sample/miku_swing_leak2/leakcounter1.cgi?s=1"); minim = new Minim(this); player = minim.loadFile("IevanPolkka_miku.mp3"); } //読み込みファイルを指定 //ローカルファイルの場合は、LocalContentProviderを使用 フルパスで記入する事。 //Httpアクセスの場合は相対アクセスでOK //content_provider = new HttpContentProvider(this, "http://www.hyde-ysd.com/reco-memo/MQOData/miku01_BONE7.mqo.txt"); // (サーバーの制限の問題で、拡張子がMQOのままUpできないため、拡張子がtxtになってます。 //miku01_xxxx.mqoは、三次元CG@七葉よりお借りしてます。利用条件はそちらに従ってください。 // 2009/4/13 //アニメーション(ぱらぱら漫画方式)は大量のモデルデータを読み込むため、 //Zip圧縮してあるデータにも対応しました。 Ver0.4以降 //LocalZipContentProvider(PAplet this, String ZipFilename, String MQOFilename) //HttplZipContentProvider(PAplet this, String ZipFile_URL, String MQOFilename) //テクスチャなどがある場合は、同じZIPファイル内に格納してください。 void loadModels() { textFont(font,15.0); fill(200,0,0); //OpenGLハンドルの取得 PGraphicsOpenGL pgl = (PGraphicsOpenGL) g; // g may change GL gl = pgl.beginGL(); // always use the GL object returned by beginGL //引数に上記に記述したファイルハンドルを入れる。 // content_provider = new LocalZipContentProvider(this, "d:\\tmp\\MQOData\\mqodatas0001.zip","mqodatas0001.mqo"); content_provider = new HttpZipContentProvider(this, "http://www.hyde-ysd.com/reco-memo/MQOData/mqodatas0002.zip","mqodatas0001.mqo"); for(int i=1;i<=n_anim;i++) { String tmpstr; // tmpstr = "e:\\tmp\\MQOData\\miku01_bone2\\mqodatas00" + (i>9 ? "":"0") +i+".mqo"; // tmpstr = "http://www.hyde-ysd.com/reco-memo/MQOData/mqodatas00" + (i>9 ? "":"0") +i+".mqo.txt"; tmpstr = "mqodatas00" + (i>9 ? "":"0") +i+".mqo"; println(tmpstr); // content_provider = new LocalContentProvider(this, tmpstr); // content_provider = new HttpContentProvider(this, tmpstr); // // ZIPファイルの場合、下記関数で読み込みファイルを指定することで、再読み込みなしで実行が可能 // 特に通信環境の時には通信量が節約できるため、ローディング時間の短縮が期待できる content_provider.ChangeEntry(tmpstr); model_data[i-1] = KGLModelData.createGLModelPs(this, gl,null,this.content_provider,0.015f, KGLExtensionCheck.IsExtensionSupported(gl,"GL_ARB_vertex_buffer_object"),true) ; gl.glBegin(LINES); gl.glVertex3f(100,100,0); gl.glVertex3f(100+int((i/n_anim)*200),100,0); gl.glEnd(); // text("("+i+"/"+n_anim+")",0,20); } //openGLハンドルの解放 pgl.endGL(); load_model = true; play_anim_no = 1; } void draw() { background(128); textFont(font,12.0); fill(200,0,0); if(load_model==false) { text("Now Loading........",0,20); loadModels(); } if(f_animation != 0) { animation_frame_up(); } text("playframe(total):" + play_frame + " show_animation_no:" + play_anim_no,0,20); text("speed:"+anim_speed,0,40); text("fps:"+getfps(),0,60); String tmpstr = ""; if(player.isMuted()==true)tmpstr+="Mute "; if(auto_mode==1)tmpstr+="Auto "; text(tmpstr,0,80); text(n_total_manual_swing+"Swing(manual)",700,20); writeInstruction(); writeCopyrights(); checkmusicstop(); PGraphicsOpenGL pgl = (PGraphicsOpenGL) g; // g may change GL gl = pgl.beginGL(); // always use the GL object returned by beginGL gl.glColor4f(0.7, 0.7, 0.7, 0.8); //おまじない gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); gl.glEnable(GL.GL_CULL_FACE); gl.glCullFace(GL.GL_FRONT); //位置調整 gl.glTranslatef(width/2, height*2/3, 0); //座標系の調整。 //(Processingは左上が0,0、一方メタセコは、中心が0,0で右上方向に軸が進むため gl.glRotatef(180, 0, 0, 1); gl.glRotatef(180, 0, 1, 0); //視点変更とか switch(camera_angle) { case 2: gl.glRotatef(-50, 1, 0, 0); break; case 3: gl.glTranslatef(0, 145, 0); gl.glRotatef(-90, 1, 0, 0); break; case 4: gl.glTranslatef(0, 0, 700); break; case 5: gl.glTranslatef(20, -80, -250); break; case 6: gl.glTranslatef(50, -150, -370); break; case 7: gl.glRotatef(20, 1, 0, 0); break; } // 描画毎に aだけ回転(デモ用) gl.glRotatef(a, 0, 1, 0); // スケールは各自調整してください。 // openGLの1.0fとは全然違うので、注意が必要。 // 枚数* // println(play_frame + " " + play_anim_no); model_data[play_anim_no].enables(100.0f) ; // model_data.draw() ; model_data[play_anim_no].draw() ; model_data[play_anim_no].disables() ; pgl.endGL(); // a += 0.5; a += hatyune_rotate_speed; play_frame += 1; } void mouseClicked() { if(f_animation == 0) { f_animation = 1; // player.resume(); if(player.isPlaying()==false) player.play(playhead); // if(player.isPlaying() == false)player.loop(); n_manual_swing++; n_total_manual_swing++; }else if(play_anim_no > 18) { f_animation += 1; n_manual_swing++; n_total_manual_swing++; } } void SendSwingData() { String[] lines = loadStrings("http://cgi.hyde-ysd.com/reco-memo/Proce55ing/sample/miku_swing_leak2/leakcounter1.cgi?n="+n_manual_swing); // n_total_manual_swing += n_manual_swing; n_manual_swing=0; } void keyPressed() { switch(key) { case 'a': if(auto_mode == 1)auto_mode = 0; else auto_mode = 1; break; case 'z': anim_speed -= 10; break; case 'c': anim_speed += 10; break; case 'r': hatyune_rotate_speed += 0.125; break; case 'R': hatyune_rotate_speed=0; break; case 'm': if(player.isMuted()==true)player.unmute(); else player.mute(); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': camera_angle = int(key)-48; break; case '8': anim_speed = 100; break; case '9': anim_speed = 350; break; } } void animation_frame_up() { anim_count += anim_speed; if(anim_count >= n_anim * 100) { anim_count %= n_anim * 100; f_animation -= 1; } play_anim_no = int(anim_count / 100); if(f_animation == 0) { if(auto_mode == 1)f_animation += 1; else { play_anim_no=0; } } } int fps_count = 1; int fps = 0; int p_t1 = 0; int getfps() { fps_count++; int tmp_t1; tmp_t1 = millis(); if(fps_count==24) { fps = 1000/((tmp_t1 - p_t1) / 24); fps_count=0; p_t1 = tmp_t1; } return fps; } void writeInstruction() { /* textFont(font2,12.0); fill(255,255,255); text("操作:",0,500); text("Mouse: L button: ネギ振り",600,520); text("振り終わりでタイミング良く押すと連続して振れます",600,520); text("Keyboard:",600,540); text("r: 回転",600,560); text("数字: 視点変更",600,560); // 実行時メモリ節約とローディング時間短縮のため英語表記にしています。 */ textFont(font,12.0); fill(255,255,255); int tmp_y_pos = 450; text("Instruction:",5,tmp_y_pos); text("Mouse: L button: Swinging leak",5,tmp_y_pos+16); text("If you push around end of animation, you can swing continuously",5,tmp_y_pos+32); text("'a' automode on/off (swing leak)",5,tmp_y_pos+48); text("r: rotaion, R:stop rotation",5,tmp_y_pos+64); text("number[1]-[7]: changing view",5,tmp_y_pos+80); text("number[8][9]: speed preset, 8:normal 9:3.5times faster",5,tmp_y_pos+96); text("z,c: change speed",5,tmp_y_pos+108); text("m: mute",5,tmp_y_pos+124); } void writeCopyrights() { // 実行時メモリ節約とローディング時間短縮のため英語表記にしています。 /* textFont(font2,12.0); fill(0,0,0); text("モデルデータ '三次元CG@七葉'",600,500); text("http://nanoha.kirara.st/3dcg/",600,520); text("モデル作成:ズサさん, モーションデータ:4169さん'",600,540); */ textFont(font,12.0); fill(0,0,0); text("Model datas come form '3DCG@nanoha'",550,500); text("http://nanoha.kirara.st/3dcg/",550,516); text("Modeled by Zusa'",550,532); text("Motion data createrd by 4169'",550,548); text("Music: IevanPolkka(miku)",550,564); text("by Otomania(http://www.otomania.net/)",550,580); } int timer_musicstop; void checkmusicstop() { if(player.isPlaying()==true && player.isLooping() == false) { if(player.position() > player.length()-1000) { player.loop(1); SendSwingData(); } } if(f_animation !=0 || player.isPlaying()==false) { timer_musicstop = 0; return; } if(timer_musicstop == 0) { timer_musicstop = millis(); } else { if(millis() - timer_musicstop > 1000) { player.pause(); playhead = player.position(); timer_musicstop = 0; SendSwingData(); } } } void stop() { // always close Minim audio classes when you are done with them SendSwingData(); player.close(); // always stop Minim before exiting. minim.stop(); super.stop(); }