網路空間異動,重建連結…
http://www.vercenter.nknu.edu.tw/flex/CarDriver/CarDriver.html
http://www.vercenter.nknu.edu.tw/flex/GoogleMapTest/GoogleMapTest.html
http://www.vercenter.nknu.edu.tw/flex/Box2DPV3D/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/FacebookFriends/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/Ribbon3dDemo/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study1/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study3/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study4/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study5/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study6/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study7/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study8/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study10/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study13/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study15/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study16/LongfellowHelloFlex.html
http://www.vercenter.nknu.edu.tw/flex/study19/LongfellowHelloFlex.html
2011年8月27日星期六
2011年7月3日星期日
學習 Android/Linux Kernel 編譯
使用 Ubuntu 11.04 (安裝在 VirtualBox 4.08) 在 emulator 上跑 Android,大致記錄過程,待有硬體再來學習實機移植…
一、安裝 git 原始碼管理套件…
sudo apt-get install git-core gnupg
二、安裝 java jre / jdk…
sudo add-apt-repository ppa:ferramroberto/java
sudo apt-get update
sudo apt-get install sun-java6-jre sun-java6-plugin
sudo apt-get install sun-java6-jdk
三、安裝其它需要的套件…
sudo apt-get install flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl valgrind
四、準備下載 Android 原始碼 (不包含Linux核心)
cd ~
wget http://Android.git.kernel.org/repo
chmod 777 repo
sudo cp repo /bin/
mkdir Android
cd Android
repo init -u git://android.git.kernel.org/platform/manifest.git
repo sync /// 這邊會下載幾小時
五、編譯/執行…
make /// 這邊會編譯幾小時
export PATH=$PATH:~/Android/out/host/linux-x86/bin
export ANDROID_PRODUCT_OUT=~/Android/out/target/product/generic
emulator
至此是 Android 的編譯,若要進行 Linux Kernel 編譯…
六、下載 Linux Kernel for Android…
mkdir kernel
cd kernel
git clone git://android.git.kernel.org/kernel/common.git /// 這邊會下載幾小時
七、透過 emulator 截取 config 檔…
cd common
emulator &
adb pull /proc/config.gz
gunzip config.gz
mv config .config
八、修改 Makefile 檔…
nano Makefile
===========================
ARCH=arm
CROSS_COMPILE ?= arm-eabi-
===========================
九、編譯…
make menuconfig
make /// 這邊會編譯幾小時
十、使用剛編譯出的核心執行 emulator…
cd ~/Android
emulator -kernel ./kernel/common/arch/arm/boot/zImage &
十一、進 Android 後台確認核心版本…
adb shell
root@android:/ # cd /proc
root@android:/proc # cat version
Linux version 2.6.29-gb0d93fb-dirty (fellong@fellong-VirtualBox) (gcc version 4.4.3 (GCC) ) #5 Sun Jul 3 14:31:58 CST 2011
一、安裝 git 原始碼管理套件…
sudo apt-get install git-core gnupg
二、安裝 java jre / jdk…
sudo add-apt-repository ppa:ferramroberto/java
sudo apt-get update
sudo apt-get install sun-java6-jre sun-java6-plugin
sudo apt-get install sun-java6-jdk
三、安裝其它需要的套件…
sudo apt-get install flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl valgrind
四、準備下載 Android 原始碼 (不包含Linux核心)
cd ~
wget http://Android.git.kernel.org/repo
chmod 777 repo
sudo cp repo /bin/
mkdir Android
cd Android
repo init -u git://android.git.kernel.org/platform/manifest.git
repo sync /// 這邊會下載幾小時
五、編譯/執行…
make /// 這邊會編譯幾小時
export PATH=$PATH:~/Android/out/host/linux-x86/bin
export ANDROID_PRODUCT_OUT=~/Android/out/target/product/generic
emulator
至此是 Android 的編譯,若要進行 Linux Kernel 編譯…
六、下載 Linux Kernel for Android…
mkdir kernel
cd kernel
git clone git://android.git.kernel.org/kernel/common.git /// 這邊會下載幾小時
七、透過 emulator 截取 config 檔…
cd common
emulator &
adb pull /proc/config.gz
gunzip config.gz
mv config .config
八、修改 Makefile 檔…
nano Makefile
===========================
ARCH=arm
CROSS_COMPILE ?= arm-eabi-
===========================
九、編譯…
make menuconfig
make /// 這邊會編譯幾小時
十、使用剛編譯出的核心執行 emulator…
cd ~/Android
emulator -kernel ./kernel/common/arch/arm/boot/zImage &
十一、進 Android 後台確認核心版本…
adb shell
root@android:/ # cd /proc
root@android:/proc # cat version
Linux version 2.6.29-gb0d93fb-dirty (fellong@fellong-VirtualBox) (gcc version 4.4.3 (GCC) ) #5 Sun Jul 3 14:31:58 CST 2011
2011年6月28日星期二
Android Starter
一、下載 JAVA SE JDK,安裝
二、下載 Android SDK,安裝
三、下載 Eclipse Classic,安裝
四、執行 Eclipse,按下列步驟安裝 ADT Plug-in (摘自 http://developer.android.com/sdk/eclipse-adt.html#installing)
五、 執行 Eclipse,到選單 > Windows > Android SDK and ADV Manager 開啟 ADV Manager (或透過直接執行 ADV Manager 亦可)。
此時若出現找不到 ADV Manager 位置的話,則要到選單 > Windows > Preferences > Andriod 頁面進行設定。
六、第一次執行 ADV Manager 要先安裝相關套件,這邊也是會開始下載安裝一段時間
七、新增加一個 ADV (Android模擬器),名稱自己取
八、OK 後就可以在 ECLIPSE 開 Android 專案了,Build Target 記得選剛剛建立好的 ADV 版本。
九、寫個範例程式…(摘自 http://developer.android.com/resources/tutorials/hello-world.html)
package example.HelloAndroid;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class HelloAndroidActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText("Hello, Android");
setContentView(tv);
}
}
十、執行結果…
二、下載 Android SDK,安裝
三、下載 Eclipse Classic,安裝
四、執行 Eclipse,按下列步驟安裝 ADT Plug-in (摘自 http://developer.android.com/sdk/eclipse-adt.html#installing)
- Start Eclipse, then select Help > Install New Software....
- Click Add, in the top-right corner.
- In the Add Repository dialog that appears, enter "ADT Plugin" for the Name and the following URL for the Location:
https://dl-ssl.google.com/android/eclipse/
- Click OK Note: If you have trouble acquiring the plugin, try using "http" in the Location URL, instead of "https" (https is preferred for security reasons).
- In the Available Software dialog, select the checkbox next to Developer Tools and click Next.
- In the next window, you'll see a list of the tools to be downloaded. Click Next.
- Read and accept the license agreements, then click Finish. Note: If you get a security warning saying that the authenticity or validity of the software can't be established, click OK.
- When the installation completes, restart Eclipse. 這邊會開始下載安裝比較久的時間。
五、 執行 Eclipse,到選單 > Windows > Android SDK and ADV Manager 開啟 ADV Manager (或透過直接執行 ADV Manager 亦可)。
此時若出現找不到 ADV Manager 位置的話,則要到選單 > Windows > Preferences > Andriod 頁面進行設定。
六、第一次執行 ADV Manager 要先安裝相關套件,這邊也是會開始下載安裝一段時間
七、新增加一個 ADV (Android模擬器),名稱自己取
八、OK 後就可以在 ECLIPSE 開 Android 專案了,Build Target 記得選剛剛建立好的 ADV 版本。
九、寫個範例程式…(摘自 http://developer.android.com/resources/tutorials/hello-world.html)
package example.HelloAndroid;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class HelloAndroidActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText("Hello, Android");
setContentView(tv);
}
}
十、執行結果…
2011年6月20日星期一
MIDI Code 在 Windows & Apple - Mac 的差別
同樣是 MIDI out 到 device,Windows 跟 Mac 卻有差別…
-----------------------------
差別一:
例如:一個 Note 「09 90 01 7f」,在 Windows 作輸出時,透過 Bus Hound (監視 USB 通訊的軟體) 來看是底下這樣…
Device Length Phase Data Description Delta Cmd.Phase.Ofs(rep)
------ -------- ----- ----------- ---------------- ----- ------------------
27.4 64 OUT 09 90 01 7f .... 5.1sc 28.1.0
00 00 00 00 .... 28.1.4
00 00 00 00 .... 28.1.8
00 00 00 00 .... 28.1.12
00 00 00 00 .... 28.1.16
00 00 00 00 .... 28.1.20
00 00 00 00 .... 28.1.24
00 00 00 00 .... 28.1.28
00 00 00 00 .... 28.1.32
00 00 00 00 .... 28.1.36
00 00 00 00 .... 28.1.40
00 00 00 00 .... 28.1.44
00 00 00 00 .... 28.1.48
00 00 00 00 .... 28.1.52
00 00 00 00 .... 28.1.56
00 00 00 00 .... 28.1.60
Windows 一次「至少」就傳了 64 bytes 的資料給 device ,後面無用的資料都補 0。
但是 Mac 卻只有傳了…「09 90 01 7f」這 4 個 bytes,並且沒有 0 作結尾。
-----------------------------
差別二:
很多 MIDI Code 要傳輸時,Windows 都是遵照上述的原則,一定會傳出 64 bytes (或許有別的 MIDI API 可以作不一樣長度的輸出,但以音控軟體 Traktor 而言是如此)
但是 Mac 在這個情況下有可能會傳出 4*N 個 bytes,也就是 4、8、12、16…。
------------------------------------
於是在韌體的撰寫上就要特別注意這二個不同的差別來作 MIDI Code 的解析,才能同時相容於 Windows 及 Mac!!!
看起來 Mac 的效能會比較好。
-----------------------------
差別一:
例如:一個 Note 「09 90 01 7f」,在 Windows 作輸出時,透過 Bus Hound (監視 USB 通訊的軟體) 來看是底下這樣…
Device Length Phase Data Description Delta Cmd.Phase.Ofs(rep)
------ -------- ----- ----------- ---------------- ----- ------------------
27.4 64 OUT 09 90 01 7f .... 5.1sc 28.1.0
00 00 00 00 .... 28.1.4
00 00 00 00 .... 28.1.8
00 00 00 00 .... 28.1.12
00 00 00 00 .... 28.1.16
00 00 00 00 .... 28.1.20
00 00 00 00 .... 28.1.24
00 00 00 00 .... 28.1.28
00 00 00 00 .... 28.1.32
00 00 00 00 .... 28.1.36
00 00 00 00 .... 28.1.40
00 00 00 00 .... 28.1.44
00 00 00 00 .... 28.1.48
00 00 00 00 .... 28.1.52
00 00 00 00 .... 28.1.56
00 00 00 00 .... 28.1.60
Windows 一次「至少」就傳了 64 bytes 的資料給 device ,後面無用的資料都補 0。
但是 Mac 卻只有傳了…「09 90 01 7f」這 4 個 bytes,並且沒有 0 作結尾。
-----------------------------
差別二:
很多 MIDI Code 要傳輸時,Windows 都是遵照上述的原則,一定會傳出 64 bytes (或許有別的 MIDI API 可以作不一樣長度的輸出,但以音控軟體 Traktor 而言是如此)
但是 Mac 在這個情況下有可能會傳出 4*N 個 bytes,也就是 4、8、12、16…。
------------------------------------
於是在韌體的撰寫上就要特別注意這二個不同的差別來作 MIDI Code 的解析,才能同時相容於 Windows 及 Mac!!!
看起來 Mac 的效能會比較好。
2010年12月16日星期四
ARM7-TDMI 第一步 - 使用 Winbond W90P710CDG 記錄
一、系統已經內建 uCLinux,先學習在上面開發 AP。
二、主板開機後連接網路線(對接或透過HUB)
三、使用 IP-Search-Utility - Etm.exe 或其它方式查詢主板 IP。
四、telnet 進去主板,登入 admin 確定 uCLinux 有跑起來。
五、安裝 Virtual Box 及 linux-Demo.vdi. 下載網址 http://www.metavert.com/public/Virtual-Linux/
六、參照 http://www.metavert.com/public/htm-w90f/21-virtual_linux.htm 說明,設定 Virtual Box 並載入 linux-Demo.vdi,或自行摸索把 linux-Demo.vdi 建成虛擬機器就是了。
七、在 Virtual Box 中啟動 linux-Demo。(Ubuntu)
八、進入 Ubuntu 後查看虛擬電腦 ip 是不是跟主板在同一子網域,若沒則作修改。看要改主板或 Ubuntu 都可。
九、將範例 g03a.tar.gz 、上載工具 tools.tar.gz 及安裝 scripts install.sh 透過共享資料夾或其它方式上傳到 Ubuntu。
十、執行 install.sh (注意查看 scripts 內容 PRJ=xxx 是否正確)
十一、安裝成功會在 home 資料夾建立範例程式,並安裝好上載工具 eUpg90
十二、開發、編輯、編譯程式,產生 目的檔 i.e. example。(最好使用 Eclipse,開發環境都設定好了,只需將 example Import 進 project 即可,真方便)
十三、在 Ubuntu 命令列,切到目的檔所在目錄,下達「eUpg90 -file -a192.168.1.10 example /usr/example」指令將 example 上傳到主板的 /usr/example 。此處 192.168.1.10 是主板的 IP。(程式需透過 eUpg90 上載,用 ftp 上傳的不行,原因還不知)
十四、telnet 主板切至 /usr 目錄應會看到上載的程式 example,執行、驗證。Good!!
完成。
*到它內建的 www 首頁就有很多範例可供參考。
二、主板開機後連接網路線(對接或透過HUB)
三、使用 IP-Search-Utility - Etm.exe 或其它方式查詢主板 IP。
四、telnet 進去主板,登入 admin 確定 uCLinux 有跑起來。
五、安裝 Virtual Box 及 linux-Demo.vdi. 下載網址 http://www.metavert.com/public/Virtual-Linux/
六、參照 http://www.metavert.com/public/htm-w90f/21-virtual_linux.htm 說明,設定 Virtual Box 並載入 linux-Demo.vdi,或自行摸索把 linux-Demo.vdi 建成虛擬機器就是了。
七、在 Virtual Box 中啟動 linux-Demo。(Ubuntu)
八、進入 Ubuntu 後查看虛擬電腦 ip 是不是跟主板在同一子網域,若沒則作修改。看要改主板或 Ubuntu 都可。
九、將範例 g03a.tar.gz 、上載工具 tools.tar.gz 及安裝 scripts install.sh 透過共享資料夾或其它方式上傳到 Ubuntu。
十、執行 install.sh (注意查看 scripts 內容 PRJ=xxx 是否正確)
十一、安裝成功會在 home 資料夾建立範例程式,並安裝好上載工具 eUpg90
十二、開發、編輯、編譯程式,產生 目的檔 i.e. example。(最好使用 Eclipse,開發環境都設定好了,只需將 example Import 進 project 即可,真方便)
十三、在 Ubuntu 命令列,切到目的檔所在目錄,下達「eUpg90 -file -a192.168.1.10 example /usr/example」指令將 example 上傳到主板的 /usr/example 。此處 192.168.1.10 是主板的 IP。(程式需透過 eUpg90 上載,用 ftp 上傳的不行,原因還不知)
十四、telnet 主板切至 /usr 目錄應會看到上載的程式 example,執行、驗證。Good!!
完成。
*到它內建的 www 首頁就有很多範例可供參考。
2010年12月4日星期六
STM32 多個外部中斷設定方式(使用stm32f10x_lib)
一、打開 GPIO 時鐘及重映射功能時鐘。
二、打開/設定 外部中斷的 中斷套嵌。
三、設置 GPIO 腳位、屬性。
四、連結 外部中斷線 到 GPIO線(PIN0~PIN15)
五、設置外部中斷反應方式並打開外部中斷
六、最後在 stm32f10x_it.c 處理中斷函式…
/* System Clocks Configuration */
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );
二、打開/設定 外部中斷的 中斷套嵌。
/* NVIC configuration */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQChannel;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQChannel;
NVIC_Init(&NVIC_InitStructure);
注意:不同的外部中斷需各別使用 NVIC_Init() 函式來設定,不可以用「|」OR 運算來同時設定。
三、設置 GPIO 腳位、屬性。
/* Configure the GPIO ports */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOE, &GPIO_InitStructure);
注意:不同的 IO PORT 需各別使用 GPIO_Init() 函式來設定,但同一個 PORT 可以用「|」OR 運算來同時設定。
四、連結 外部中斷線 到 GPIO線(PIN0~PIN15)
/* Connect EXTI Line to GPIO Pin */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3);
注意:不同 GPIO Pin 需各別使用 GPIO_EXTILineConfig() 函式來設定,不可以用「|」OR 運算來同時設定。
五、設置外部中斷反應方式並打開外部中斷
/* Configure EXTI Line to generate an interrupt on falling edge */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3;
EXTI_Init(&EXTI_InitStructure);
注意:所有的外部中斷可以使用一次/多次 EXTI_Init() 函式來設定,並可以用「|」OR 運算來同時設定。
六、最後在 stm32f10x_it.c 處理中斷函式…
void EXTIx_IRQHandler(void)
{
}
2010年12月2日星期四
RL-ARM 使用 user timer 的方法
一、在 RTX_Config.c 修改 OS_TIMERCNT。(預設是 0 記得要修改)
二、在 task 中建立 timer。
三、在 RTX_Config.c 修改 timer 的 callback 函式 os_tmr_call。
#ifndef OS_TIMERCNT
#define OS_TIMERCNT 5
#endif
二、在 task 中建立 timer。
OS_ID tmr1;
tmr1 = os_tmr_create (300, 1); /// after 300 system_tick, callback.
if (tmr1 == NULL) {
printf ("Failed to create user timer.\n");
}
三、在 RTX_Config.c 修改 timer 的 callback 函式 os_tmr_call。
void os_tmr_call (U16 info) {
/* This function is called when the user timer has expired. Parameter */
/* 'info' holds the value, defined when the timer was created. */
/* HERE: include optional user code to be executed on timeout. */
}
2010年10月28日星期四
時間轉換函式~秒<---->日期 (從2000年)
bit isleap(int y)
{
return y%4==0&&y%100!=0 || y%400==0;
}
int DaysOfMonth( int y, int m )
{
switch(m)
{
case 1: return 31;
case 2: return isleap(y)?29:28;
case 3: return 31;
case 4: return 30;
case 5: return 31;
case 6: return 30;
case 7: return 31;
case 8: return 31;
case 9: return 30;
case 10: return 31;
case 11: return 30;
case 12: return 31;
}
return 30;
}
int DaysOfYear( int y )
{
if( isleap(y) )
return 366;
return 365;
}
unsigned long SecsFrom2000( int y, int m, int d, int hh, int mm, int ss )
{
int i;
unsigned long day = 0;
for( i=2000; i<y; i++ )
day += DaysOfYear(i);
for( i=1; i<m; i++ )
day += DaysOfMonth(y,i);
day += d;
day = day*86400L + hh*3600L + mm*60L + ss*1L;
return day;
}
void SecToDateTime( unsigned long sec, cdate * pdate, ctime * ptime )
{
unsigned long day;
day = sec/86400;
pdate->yy = 2000;
while( day > DaysOfYear( pdate->yy ) )
{
day-= DaysOfYear( pdate->yy );
pdate->yy++;
}
pdate->mm = 1;
while( day > DaysOfMonth( pdate->yy, pdate->mm ) )
{
day-= DaysOfMonth( pdate->yy, pdate->mm );
pdate->mm++;
}
pdate->dd = day;
ptime->hh = (sec/3600)%24;
ptime->mm = (sec/60)%60;
ptime->ss = (sec)%60;
}
2010年6月23日星期三
MS OFFICE 2007 .ppsx 檔轉檔
先下載安裝 Open office
http://download.openoffice.org/index.html
使用 Open office 開啟 ppsx 檔
開啟時會詢問你使用的 filter 篩選器
此時選 ms office 2007 即可開啟
再另存新檔 ms office 97 格式即可
http://download.openoffice.org/index.html
使用 Open office 開啟 ppsx 檔
開啟時會詢問你使用的 filter 篩選器
此時選 ms office 2007 即可開啟
再另存新檔 ms office 97 格式即可
2010年6月22日星期二
Visual Studio 2010
幾個 VB 的技巧…
Callback 函式指定方式
SerialPort1_DataReceived 因為是執行緒非同步在接收 RS232 的資料,而 VB 不允許在執行緒中直接設定一些 Components 的值,因些必須透過代理的方式來處理…
String 跟 char array 轉換的方式…
要加快 components 的繒圖速度可以使用 GDI 雙重緩衝,若是繼承自 compnents 可寫在 New() 建構式中…
Callback 函式指定方式
AddHandler _timer.Tick, AddressOf TimerEventProcessor
Private Sub TimerEventProcessor(ByVal myObject As Object, ByVal myEventArgs As EventArgs)
'todo
End Sub
SerialPort1_DataReceived 因為是執行緒非同步在接收 RS232 的資料,而 VB 不允許在執行緒中直接設定一些 Components 的值,因些必須透過代理的方式來處理…
Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
memoMessage.Invoke(New myDelegate(AddressOf updateTextBox), New Object() {})
End Sub
Public Delegate Sub myDelegate()
Public Sub updateTextBox()
memoMessage.Text = SerialPort1.ReadExisting()
End Sub
String 跟 char array 轉換的方式…
Dim str as String
Dim carr() As Char = str.ToCharArray
str = CStr(carr)
要加快 components 的繒圖速度可以使用 GDI 雙重緩衝,若是繼承自 compnents 可寫在 New() 建構式中…
Public Sub New()
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Me.SetStyle(ControlStyles.UserPaint, True)
End Sub
2010年5月31日星期一
Android 開發 Google Map API - 如何註冊 API Key
Google Map View 官方教學網站…
http://developer.android.com/resources/tutorials/views/hello-mapview.html
這有詳盡的 Android Google API 開發教學~
萬事起頭難,其中提到,必須有一組 API Key 才能註冊成為合法認證的 Google API,才能在 Android 上執行,才可以開始玩。(其實就是 java 憑證)
建立過程如下…
一、在開發的過程中,可以先建立 debug certificate…
http://code.google.com/intl/zh-TW/android/add-ons/google-apis/mapkey.html#getdebugfingerprint
二、按照上面的說明,先找到應用程式存放 debug keystore 的地方,通常放在…
C:\Documents and Settings\<user>\.android\debug.keystore
或可透過裝了 ADT 的 Eclipse 選單 Windows > Prefs > Android > Build 中找到完整路徑。
三、再下達…
keytool -list -alias androiddebugkey -keystore <path_to_debug_keystore>.keystore -storepass android -keypass android
會發生二個問題…
四、如此便會算出 MD5 碼…
androiddebugkey, 2010/5/15, keyEntry,
認證指紋 (MD5): 70:02:A3:1F:85:35:D1:A4:3C:1C:D2:12:34:56:78:90
五、有了 MD5 碼就可以到 Android Maps API Key Signup 網頁註冊新的 API Key…
http://code.google.com/intl/zh-TW/android/maps-api-signup.html
六、完成註冊,得到 API Key…
感謝您申請 Android Maps API 金鑰!
您的金鑰為:
0GNWKtyf-6M2YDIU3XIjq-Qgqh0yn1234567890
此金鑰適合所有使用以下指紋憑證所簽署的應用程式:
70:02:A3:1F:85:35:D1:A4:3C:1C:D2:12:34:56:78:90
有了金鑰就可以拿來填到 main.xml 中了。
p.s. 下達 keytool 指令時可以善用 DOS 輸出導向功能 keytool ooo xxx yyy ... zzz > md5.txt , 把輸出導向到一個檔案方便拷貝,以免打錯 MD5 碼。
http://developer.android.com/resources/tutorials/views/hello-mapview.html
這有詳盡的 Android Google API 開發教學~
萬事起頭難,其中提到,必須有一組 API Key 才能註冊成為合法認證的 Google API,才能在 Android 上執行,才可以開始玩。(其實就是 java 憑證)
建立過程如下…
一、在開發的過程中,可以先建立 debug certificate…
http://code.google.com/intl/zh-TW/android/add-ons/google-apis/mapkey.html#getdebugfingerprint
二、按照上面的說明,先找到應用程式存放 debug keystore 的地方,通常放在…
C:\Documents and Settings\<user>\.android\debug.keystore
或可透過裝了 ADT 的 Eclipse 選單 Windows > Prefs > Android > Build 中找到完整路徑。
三、再下達…
keytool -list -alias androiddebugkey -keystore <path_to_debug_keystore>.keystore -storepass android -keypass android
會發生二個問題…
- keytool.exe 的位置:在 JAVA JRE 安裝目錄中,例如…
C:\Program Files\Java\jre6\bin
- 路徑有可能包含空白字元,導致無法在 DOS COMMAND 視窗下達指令,你可以先把 debug.keystore 拷貝到 C:\ 再下達指令…
keytool -list -alias androiddebugkey -keystore c:\debug.keystore -storepass android -keypass android
四、如此便會算出 MD5 碼…
androiddebugkey, 2010/5/15, keyEntry,
認證指紋 (MD5): 70:02:A3:1F:85:35:D1:A4:3C:1C:D2:12:34:56:78:90
五、有了 MD5 碼就可以到 Android Maps API Key Signup 網頁註冊新的 API Key…
http://code.google.com/intl/zh-TW/android/maps-api-signup.html
六、完成註冊,得到 API Key…
感謝您申請 Android Maps API 金鑰!
您的金鑰為:
0GNWKtyf-6M2YDIU3XIjq-Qgqh0yn1234567890
此金鑰適合所有使用以下指紋憑證所簽署的應用程式:
70:02:A3:1F:85:35:D1:A4:3C:1C:D2:12:34:56:78:90
有了金鑰就可以拿來填到 main.xml 中了。
p.s. 下達 keytool 指令時可以善用 DOS 輸出導向功能 keytool ooo xxx yyy ... zzz > md5.txt , 把輸出導向到一個檔案方便拷貝,以免打錯 MD5 碼。
2010年5月23日星期日
Android EventListener 建立方法
元件常常有很多「event」必預要去「listen」,這時候需要靠 EventListener。
網路上看到的範例大多長的像底下這個樣子…
乍看可能還很難以理解這一小段程式是在作什麼,其實整個意義如同底下這段程式…
也就是它其實是建立了個新的 class implements 原來的 OnClickListener 來自訂 onClick 事件處理函式。
但難的是在 coding 的時候往往不曉得(或忘了)有哪些事件,有哪些 listener,更別說要寫出上面第一段那樣的程式了。
還好 Eclipse 開發環境很好用,你可以利用它自動產生程式碼的功能,幫你做到這些事。
用說的不好解釋,看段影片說明…
http://www.youtube.com/v/plW4zMxpnBA
這樣就可以減輕腦袋的負荷了~^ ^
網路上看到的範例大多長的像底下這個樣子…
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
/// TODO
}
});
乍看可能還很難以理解這一小段程式是在作什麼,其實整個意義如同底下這段程式…
btn.setOnClickListener( new clsOnClickListener() );
///---inline class ---///
public class clsOnClickListener implements OnClickListener {
public void onClick(View v) {
/// TODO
}
}
也就是它其實是建立了個新的 class implements 原來的 OnClickListener 來自訂 onClick 事件處理函式。
但難的是在 coding 的時候往往不曉得(或忘了)有哪些事件,有哪些 listener,更別說要寫出上面第一段那樣的程式了。
還好 Eclipse 開發環境很好用,你可以利用它自動產生程式碼的功能,幫你做到這些事。
用說的不好解釋,看段影片說明…
http://www.youtube.com/v/plW4zMxpnBA
這樣就可以減輕腦袋的負荷了~^ ^
Android 動態產生元件
Android 應用程式的開發一般都將 UI 跟 RESOURCES 的部分抽離出來,好方便管理及設計,也因此有一些 XML 檔需要撰寫,主要都是用來描述這些資源。
但若要自己土法練鋼寫動態產生時要怎麼作?
相對照若用 xml 來描述的話像這樣…
但若要自己土法練鋼寫動態產生時要怎麼作?
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
///setContentView(R.layout.main); ///不使用 main.xml 資源
LinearLayout layout = new LinearLayout(this);
this.addContentView(layout, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
layout.setOrientation(LinearLayout.VERTICAL);
Button btn = new Button(this);
btn.SetText("Button");
layout.addView(btn, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
EditText txt = new EditText(this);
layout.addView(txt, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
相對照若用 xml 來描述的話像這樣…
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:text="Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
</Button>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</EditText>
</LinearLayout>
Android TabLayout 使用心得
Android 2.2 SDK 己經出了…
http://developer.android.com/sdk/index.html
最近也在學習,還好之前有 java/javaME 的基礎,還算順利。
Google 官方有提供教學網頁…
http://developer.android.com/resources/index.html
很不錯。
不過其中一個範例 TabLayout 的使用…
http://developer.android.com/resources/tutorials/views/hello-tabwidget.html
這個範例對初學者來講比較複雜。
底下是比較簡單易理解的版本…
HelloTabWidgetNoIcon.java
main.xml
對照一下 HelloTabWidgetNoIcon.java 及 main.xml 就可以了解程式碼跟 layout 間的對應關係了(tab0,tab1,tab2)。
跟官方的範例不同的地方在於,官方的還多加了…
一、Tab 的小圖示( ic_tab_artists.xml, ic_tab_albums.xml, ic_tab_songs.xml 及圖片 )
二、動態的 Tab View ( ArtistsActivity.java, AlbumsActivity.java, SongsActivity.java )
所以才比較複雜並且要多撰寫一些 xml 碼。
不過,若真的要用在手機上,當然還是用圖示比較吸引人嘍。
http://developer.android.com/sdk/index.html
最近也在學習,還好之前有 java/javaME 的基礎,還算順利。
Google 官方有提供教學網頁…
http://developer.android.com/resources/index.html
很不錯。
不過其中一個範例 TabLayout 的使用…
http://developer.android.com/resources/tutorials/views/hello-tabwidget.html
這個範例對初學者來講比較複雜。
底下是比較簡單易理解的版本…
HelloTabWidgetNoIcon.java
package com.study.HelloTabWidgetNoIcon;
import android.app.TabActivity;
import android.os.Bundle;
import android.widget.TabHost;
public class HelloTabWidgetNoIcon extends TabActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TabHost tabHost = getTabHost(); // The activity TabHost
TabHost.TabSpec spec; // Resusable TabSpec for each tab
// Initialize a TabSpec for each tab and add it to the TabHost
spec = tabHost.newTabSpec("artists").setIndicator("Artists").setContent(R.id.tab0);
tabHost.addTab(spec);
// Do the same for the other tabs
spec = tabHost.newTabSpec("albums").setIndicator("Albums").setContent(R.id.tab1);
tabHost.addTab(spec);
spec = tabHost.newTabSpec("songs").setIndicator("Songs").setContent(R.id.tab2);
tabHost.addTab(spec);
tabHost.setCurrentTab(0);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp" >
<TextView
android:text="tab0"
android:id="@+id/tab0"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="tab1"
android:id="@+id/tab1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="tab2"
android:id="@+id/tab2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
</LinearLayout>
</TabHost>
對照一下 HelloTabWidgetNoIcon.java 及 main.xml 就可以了解程式碼跟 layout 間的對應關係了(tab0,tab1,tab2)。
跟官方的範例不同的地方在於,官方的還多加了…
一、Tab 的小圖示( ic_tab_artists.xml, ic_tab_albums.xml, ic_tab_songs.xml 及圖片 )
二、動態的 Tab View ( ArtistsActivity.java, AlbumsActivity.java, SongsActivity.java )
所以才比較複雜並且要多撰寫一些 xml 碼。
不過,若真的要用在手機上,當然還是用圖示比較吸引人嘍。
2010年5月2日星期日
申請使用GoogleApps免費服務記錄
Google Apps 是 GOOGLE 提供的一項很好用的服務,提供免費的網頁、EMAIL服務…,一些小公司、小企業、社群團體都應該考慮使用這項免費的服務,其中EMAIL服務算是最重要的,有了這個,你再也不用自己架設、管理MAIL伺服器,可以節省一大筆開銷又能同時獲得很穩定的EMAIL服務(己使用二年的經驗來看算是非常穩定的)
你需要…
一個有效的網域名稱 ( 可以申請免費服務 )
一台DNS伺服器 ( 可以申請免費服務 )
一台網頁伺服器 ( 驗證用,透過其它驗證方式,可以省掉不用 )
換句話說,你完全不需要準備任何伺服器,就可以完成 GOOGLE APPS 服務的申請。
底下是簡單的申請步驟抓圖記錄
到申請首頁輸入你的網域名稱(透過購買或從網路上申請免費網域名稱)
輸入申請資料
輸入管理理帳戶資料
初步申請完成
進行「網域名稱驗證」,以驗證這個網域確實是你的,二種驗證方式,CNAME不需要主機,只需要DNS服務,網頁方式則需要透過上傳網頁的方式來進行,選取後GOOGLE會導引你進行驗證。
這邊是使用網頁的方式進行驗證(需要有自己的網頁伺服器)
再來是EMAIL的設定,需要設定DNS的MX記錄,指向GOOGLE的MAIL管理伺服器,才能讓GOOGL順利利用此網域收發信
這邊使用免費網域twbbs,設定MX記錄讓EMAIL生效
幾小時後,你的email服務就可以使用了!!
2010年4月29日星期四
GOOGLE MAP 導航
使用 FLEX 測試 GOOGLE MAP API ,簡單的導航功能的應用。
線上DEMO:
http://www.asn.com.tw/flex/GoogleMapTest/GoogleMapTest.html
20110827連結更新…
http://www.vercenter.nknu.edu.tw/flex/GoogleMapTest/GoogleMapTest.html
mxml 原始碼:
http://docs.google.com/Doc?docid=0AQb8tm8yloBcZGZ2NnhuNWRfMTgwN2Q5NjlkcWNq&hl=zh_TW
參考教學:
http://code.google.com/intl/zh-TW/apis/maps/documentation/flash/
關鍵字:Marker,Directions,ClientGeocoder
線上DEMO:
http://www.asn.com.tw/flex/GoogleMapTest/GoogleMapTest.html
20110827連結更新…
http://www.vercenter.nknu.edu.tw/flex/GoogleMapTest/GoogleMapTest.html
mxml 原始碼:
http://docs.google.com/Doc?docid=0AQb8tm8yloBcZGZ2NnhuNWRfMTgwN2Q5NjlkcWNq&hl=zh_TW
參考教學:
http://code.google.com/intl/zh-TW/apis/maps/documentation/flash/
關鍵字:Marker,Directions,ClientGeocoder
2010年4月27日星期二
2010年3月19日星期五
FLEX AIR 包裝應用程式 ICON 的問題
在開發 AIR 應用程式後,若要包裝自己的應用程式,並且加上自訂的圖示的話,可以到 project\src\your-app.xml 找到…
<!-- <icon>
<image16x16></image16x16>
<image32x32></image32x32>
<image48x48></image48x48>
<image128x128></image128x128>
</icon> -->
修改成…
<icon>
<image32x32>images/icon.png</image32x32>
</icon>
要注意,若你只有一個 32x32 的 ICON 就只要留下 <image32x32></image32x32> 這行即可,千萬別把其它留空白,否則會包裝失敗還一直查不出原因…錯誤示範如下…
<icon>
<image16x16></image16x16>
<image32x32>images/icon.png</image32x32>
<image48x48></image48x48>
<image128x128></image128x128>
</icon>
<!-- <icon>
<image16x16></image16x16>
<image32x32></image32x32>
<image48x48></image48x48>
<image128x128></image128x128>
</icon> -->
修改成…
<icon>
<image32x32>images/icon.png</image32x32>
</icon>
要注意,若你只有一個 32x32 的 ICON 就只要留下 <image32x32></image32x32> 這行即可,千萬別把其它留空白,否則會包裝失敗還一直查不出原因…錯誤示範如下…
<icon>
<image16x16></image16x16>
<image32x32>images/icon.png</image32x32>
<image48x48></image48x48>
<image128x128></image128x128>
</icon>
FMS串流撥放FLV(或RTMP)時截取其BITMAP的方式
在透過 FMS 撥放 rtmp 串流影音時,若你的 CLIENT 端除了撥放,還要抓圖作處理的話,會遇到如下的例外…
SecurityError: Error #2123: Security sandbox violation:
BitmapData.draw: file:///xxx/xxx/xxx.swf
cannot access rtmp://xxx.xxx.xxx/live. No policy files granted access.
解決方式如下…
1. COPY 安裝範例 C:\Program Files\Adobe\Flash Media Server 3.5\samples\applications\vod 到你自己的應用程式。(有興趣可以研究看看其寫法)
2. 修改 Application.xml 檔,在 <client></client> 區間加入…
<Access>
<VideoSampleAccess enabled="true">/</VideoSampleAccess>
</Access>
3. 修改 main.asc (即 Server-side-code)…
找到 application.onConnect = function( p_client, p_autoSenseBW )
這邊是用來處理當有 client 連到這個 server app 時的對應函式,幾個相關參數設定如下…
writeAccess:
若你有用到 shared object 或 live streams,就把它註解掉
//p_client.writeAccess = ""; // prevents creating shared object or live streams.
audioSampleAccess:
允許 client side 直接抓取音效 raw data,利用 SoundMixer.computeSpectrum() 處理音效
p_client.audioSampleAccess = "/";
audioSampleAccess:
允許 client side 直接抓取影片 raw data,利用 BitmapData.draw() 抓圖
p_client.videoSampleAccess = "/";
參考這篇: http://www.thebluepipe.com/Developer/tutorials/as3/Crossdomain-Video-Snapshot-Fixing-BitmapData-draw-Security-Sandbox-Violation.html
SecurityError: Error #2123: Security sandbox violation:
BitmapData.draw: file:///xxx/xxx/xxx.swf
cannot access rtmp://xxx.xxx.xxx/live. No policy files granted access.
解決方式如下…
1. COPY 安裝範例 C:\Program Files\Adobe\Flash Media Server 3.5\samples\applications\vod 到你自己的應用程式。(有興趣可以研究看看其寫法)
2. 修改 Application.xml 檔,在 <client></client> 區間加入…
<Access>
<VideoSampleAccess enabled="true">/</VideoSampleAccess>
</Access>
3. 修改 main.asc (即 Server-side-code)…
找到 application.onConnect = function( p_client, p_autoSenseBW )
這邊是用來處理當有 client 連到這個 server app 時的對應函式,幾個相關參數設定如下…
writeAccess:
若你有用到 shared object 或 live streams,就把它註解掉
//p_client.writeAccess = ""; // prevents creating shared object or live streams.
audioSampleAccess:
允許 client side 直接抓取音效 raw data,利用 SoundMixer.computeSpectrum() 處理音效
p_client.audioSampleAccess = "/";
audioSampleAccess:
允許 client side 直接抓取影片 raw data,利用 BitmapData.draw() 抓圖
p_client.videoSampleAccess = "/";
參考這篇: http://www.thebluepipe.com/Developer/tutorials/as3/Crossdomain-Video-Snapshot-Fixing-BitmapData-draw-Security-Sandbox-Violation.html
2010年1月12日星期二
PHP中計算某一周的起始及結束日期
以星期日為一周起始,函式傳入年份及第幾周,函式傳出開始及結束日期。
function findWeekPeriod( $week, $year )
{
$aPeriod = array();
$first_day = strtotime($year."-01-01");
$is_week_first_day = date("w", $first_day) == 0;
$is_weekone = strftime("%V", $first_day) == 1;
if($is_weekone)
{
$week_one_start = $is_week_first_day ? strtotime("last sunday",$first_day) : $first_day;
}
else
{
$week_one_start = strtotime("next sunday", $first_day);
}
$aPeriod['start'] = date("Y年m月d日", $week_one_start+(3600*24*7*($week-1)) );
$aPeriod['end'] = date("Y年m月d日", $week_one_start+(3600*24*(7*$week-1)) );
return $aPeriod;
}
例如…
$week=date('W');
$year=date('Y');
$wPeriod=findWeekPeriod( $week, $year );
/// 傳回當周的起始結束日期。
function findWeekPeriod( $week, $year )
{
$aPeriod = array();
$first_day = strtotime($year."-01-01");
$is_week_first_day = date("w", $first_day) == 0;
$is_weekone = strftime("%V", $first_day) == 1;
if($is_weekone)
{
$week_one_start = $is_week_first_day ? strtotime("last sunday",$first_day) : $first_day;
}
else
{
$week_one_start = strtotime("next sunday", $first_day);
}
$aPeriod['start'] = date("Y年m月d日", $week_one_start+(3600*24*7*($week-1)) );
$aPeriod['end'] = date("Y年m月d日", $week_one_start+(3600*24*(7*$week-1)) );
return $aPeriod;
}
例如…
$week=date('W');
$year=date('Y');
$wPeriod=findWeekPeriod( $week, $year );
/// 傳回當周的起始結束日期。
2010年1月5日星期二
AS3 Face Detection 練習
臉部辨識練習。
測試影片:
http://www.youtube.com/watch?v=EHocW-Bkqkc
線上DEMO:(需有 Webcam 視訊,正面對鏡頭)
http://www.asn.com.tw/flex/FaceDetector/FaceDetectorXML.html
參考網站:
http://www.squidder.com/2009/02/26/realtime-face-detection-in-flash/
這個網站以 OpenCV 為基礎,改寫成 flash 版本,效能不錯。
這邊還有一個網站有把它作些優化…
http://www.quasimondo.com/archives/000687.php
主要是 haarcascade 檔的載入把它轉成一個靜態的類別,但這樣變成只能作臉部辨識,haarcascade 就不能動態載入了。
*haarcascade 檔是拿來述描所要辨識的影像的特徵集。
squidder 載入的 haarcascade 檔是一個包含 Adler-32 Checksum 的 ZIP 壓縮檔,使用上比較不方便,我用了 nochump 的 ZIP LIB 寫了一個簡單的 ZipLoader.as 來給這個 DEMO 使用,好方便載入不同的 haarcascade 檔,使用時只要把 HaarCascadeLoader.as 原始檔中的 "import jp.maaash.net.ZipLoader" REMARK 掉即可(當然,你還要有 nochump 的 ZIP LIB)。
有試過安裝 OpenCV 並使用它的其它 haarcascade 檔,例如手部、眼睛…,可惜沒有辨識成功~"~,還需要再研究。
ZipLoader.as...
package
{
import nochump.util.zip.*;
import flash.events.EventDispatcher;
import flash.events.Event;
import flash.net.URLRequest;
import flash.utils.IDataInput;
import flash.utils.ByteArray;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
public class ZipLoader extends EventDispatcher{
private var debug:Boolean;
private var _url:String;
private var req:URLRequest;
private var data:ByteArray;
public function ZipLoader(d:Boolean=false){
debug = d;
req = new URLRequest;
}
public function load():void{
var xmlLoader:URLLoader = new URLLoader();
xmlLoader.addEventListener(Event.COMPLETE, onLoadXML);
xmlLoader.dataFormat = URLLoaderDataFormat.BINARY;
xmlLoader.load(req);
}
public function onLoadXML(e:Event):void
{
var zipFile:ZipFile = new ZipFile(e.target.data);
var entry:ZipEntry = zipFile.entries[0];
//trace(entry.name);
// extract the entry's data from the zip
data = zipFile.getInput(entry);
//trace(data.toString());
dispatchEvent( e.clone() );
}
public function set url(u:String):void{
_url = u;
req.url = _url;
}
public function getContentAsString():String{
return data.toString();
}
private function logger(... args):void{
if(!debug){ return; }
log(["[ZipLoader]"+args.shift()].concat(args));
}
}
}
測試影片:
http://www.youtube.com/watch?v=EHocW-Bkqkc
線上DEMO:(需有 Webcam 視訊,正面對鏡頭)
http://www.asn.com.tw/flex/FaceDetector/FaceDetectorXML.html
參考網站:
http://www.squidder.com/2009/02/26/realtime-face-detection-in-flash/
這個網站以 OpenCV 為基礎,改寫成 flash 版本,效能不錯。
這邊還有一個網站有把它作些優化…
http://www.quasimondo.com/archives/000687.php
主要是 haarcascade 檔的載入把它轉成一個靜態的類別,但這樣變成只能作臉部辨識,haarcascade 就不能動態載入了。
*haarcascade 檔是拿來述描所要辨識的影像的特徵集。
squidder 載入的 haarcascade 檔是一個包含 Adler-32 Checksum 的 ZIP 壓縮檔,使用上比較不方便,我用了 nochump 的 ZIP LIB 寫了一個簡單的 ZipLoader.as 來給這個 DEMO 使用,好方便載入不同的 haarcascade 檔,使用時只要把 HaarCascadeLoader.as 原始檔中的 "import jp.maaash.net.ZipLoader" REMARK 掉即可(當然,你還要有 nochump 的 ZIP LIB)。
有試過安裝 OpenCV 並使用它的其它 haarcascade 檔,例如手部、眼睛…,可惜沒有辨識成功~"~,還需要再研究。
ZipLoader.as...
package
{
import nochump.util.zip.*;
import flash.events.EventDispatcher;
import flash.events.Event;
import flash.net.URLRequest;
import flash.utils.IDataInput;
import flash.utils.ByteArray;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
public class ZipLoader extends EventDispatcher{
private var debug:Boolean;
private var _url:String;
private var req:URLRequest;
private var data:ByteArray;
public function ZipLoader(d:Boolean=false){
debug = d;
req = new URLRequest;
}
public function load():void{
var xmlLoader:URLLoader = new URLLoader();
xmlLoader.addEventListener(Event.COMPLETE, onLoadXML);
xmlLoader.dataFormat = URLLoaderDataFormat.BINARY;
xmlLoader.load(req);
}
public function onLoadXML(e:Event):void
{
var zipFile:ZipFile = new ZipFile(e.target.data);
var entry:ZipEntry = zipFile.entries[0];
//trace(entry.name);
// extract the entry's data from the zip
data = zipFile.getInput(entry);
//trace(data.toString());
dispatchEvent( e.clone() );
}
public function set url(u:String):void{
_url = u;
req.url = _url;
}
public function getContentAsString():String{
return data.toString();
}
private function logger(... args):void{
if(!debug){ return; }
log(["[ZipLoader]"+args.shift()].concat(args));
}
}
}
2009年12月30日星期三
FlarDetector - make a hole underground
http://www.youtube.com/watch?v=CW9imHbbljU
使用 FlarDetector 作成的地洞測試影片,加上在 3DS MAX 作的 miku 動畫、彩虹及程式中運算的 3D 彈跳球。
project source ...
http://code.google.com/p/flardetector/
使用 FlarDetector 作成的地洞測試影片,加上在 3DS MAX 作的 miku 動畫、彩虹及程式中運算的 3D 彈跳球。
project source ...
http://code.google.com/p/flardetector/
2009年12月22日星期二
FLARToolKit Multi Marker Detector & Cube type Marker 實作
ARis...
ARis 是日本一間公司出品的產品,應用了 ARToolKit 技術。
展示影片在這…
http://www.youtube.com/watch?v=yCCx7zANsGE
YouTube上可以找到更多類似的影片。
這邊是我用 FLARToolKit 自己作的 DEMO,當然,不止是能運用在這方面( 指宅男專用 ),像是商業產品的3D 展示也可以這樣用,在全像投影真正普及化實現之前,我想 AR 技術或許是最快實現類似體驗的方法吧? ( 配合 AR 眼鏡 )
DEMO VIDEO...
http://www.youtube.com/watch?v=W9s2ldmd9Vc
DEMO ONLINE...
http://www.asn.com.tw/flex/FlarMikuDemo/PV3DFlarTest.html
要線上執行需要列印出上列 Marker 檔,將其中的方塊組合起來,並且準備一台 Webcam,程式運行後再將 Webcam 對準方塊就會出現人偶嘍~(還有牛)!!!
Markers...
ARis Marker : http://www.asn.com.tw/flex/FlarMikuDemo/Data/ARisMarker.jpg
Cube Marker : http://www.asn.com.tw/flex/FlarMikuDemo/Data/CubeMarker.jpg
要自建 Marker 檔可以到…
http://flash.tarotaro.org/blog/2008/12/14/artoolkit-marker-generator-online-released/
======== 底下給有興趣寫 AR 程式的人作參考 ========
MultiMarker...
這個程式等於是 FLARToolKit 複數 Marker 的應用,在 FLARToolKit 中有個 FLARMultiMarkerDetector 的類別,是用來同時偵測多個 Marker 用的,MultiMarker 的偵測需要管理多個 Maeker 的 ARCode。
網路上有現成的多偵測點 Marker 管理函式庫 FLARManager…
這個 MultiMarker 管理類別功能蠻強大的,包含多點偵測、圖形二元化閥值最佳化、座標位置 smooth 及動態點預測…。
FlarDetetor...
不過我沒有實際去用 FLARManager,而是自己寫了個簡化版的 FlarDetetor,一樣是 MultiMarker Detect,還蠻好用的,我的 ARis 就是利用這個類別作出來的。
FlarDetetor 特色:
一、多個 Marker 同時偵測。
二、事件觸發 ( MARKER_ADDED、MARKER_UPDATED、MARKER_REMOVED )。
三、完全獨立的一個類別,低耦合,只用到原始的 FLARToolKit 類別。
四、俱備簡易 smooth 功能。
如何使用:
一、初始化,跟一般 FLARToolKit 應用程式一樣代入 FLARParam 跟 Webcam 的 Bitmapdata。
二、 建立 FlarObject 物件並載入 Marker 檔,然後加入 PV3D scene 中。
var cube:FlarCube = new FlarCube ();
cube.detector.loadCode( 'cube.pat',16,100 ); /// 注意後面二個 width 參數要與當初存 patern 時一致,否則測不出來唷。
三、最後只要在 PV3D Render 的時候 detect 即可自動分派事件。
FlarObject...
這個類別便是拿來裝你的 PV3D 子物件的容器,繼承自 FLARToolKit 的 FLARBaseNode 類別,並且有基本的一個 FlarDetector 及預設的事件反應,當 FlarDetector偵測到時便進行座標方位的轉換。
比較特別的地方在於我使用了一個 _pivot:DisplayObject3D 作為內容器,好方便底下延伸類別的座標軸轉換,所有子物件都放在 pivot中,就可以自由在程式控制相對位置跟方向,而不會受 Node Transform 的影響。
當然,其實 FlarDetector 是蠻低耦合的一個類別,你也可以直接使用 FlarDetector 在任何的場合,創造你自己的類別,也不一定要配合 PV3D 來使用,把 FlarDetector 當成一個單純的 Sensor 來使用即可。
FlarARisCube...
至於六面體 Marker 的偵測,網路上可以找到 Tarotaro 的 5 面立方體範例…
http://flash.tarotaro.org/blog/2009/04/06/cube-type-marker-in-flar/
他的演算法是將水平的四個面用二個 Marker 解決,一個偵測用,一個判斷面向用,再加上上面一個 Marker 總共三個,真聰明丫,詳細的演算法可以參考…
http://flash.tarotaro.org/blog/2009/06/10/about-cube-detection-algorithm/
但是可惜是這個方法只能作 5 面偵測,從底下往上看沒有(要幹嘛?!),而且水平的四個面的 Marker 必需有一定的規則,Marker 的設計要比較注意。
這 個函式庫我也沒實際去用,於是又寫了個 FlarARisCube 的類別,這個類別其實只是在一個類別中放了六個 FlarDetector,再在偵測到時轉換一下座標而己,只是在轉換座標時搞的有點暈頭轉向,我的方法是比較直接的方式,效能沒 Tarotaro 的好,只能說是比較容易實現的方法。
最後則是六面體方塊在上仰角度時,會有遮罩的效果,讓六面體看起來更直實(能遮到人偶),我是參考 FLARToolKit 的原作者 saqoosha 的這篇文章…
http://saqoosha.net/en/2009/01/08/1676/
文章是介紹地上打洞的效果,不過原理一樣 ( 地上打洞很酷丫,下回再來作 ^ ^ )。
Finally…
一連串的學習QQ",總算成功,出現人偶嘍~(還有牛)~呵呵呵。
Source Code...
原始程式下載:( 包含 papervision3d 及 flartoolkit )-原始版本
http://www.asn.com.tw/flex/FlarMikuDemo/FlarMikuDemo.zip
2009/12/22 - 最新的 source 改放在 google code,http://code.google.com/p/flardetector/
( 不包含 papervision3d 及 flartoolkit )
ARis 是日本一間公司出品的產品,應用了 ARToolKit 技術。
展示影片在這…
http://www.youtube.com/watch?v=yCCx7zANsGE
YouTube上可以找到更多類似的影片。
這邊是我用 FLARToolKit 自己作的 DEMO,當然,不止是能運用在這方面( 指宅男專用 ),像是商業產品的3D 展示也可以這樣用,在全像投影真正普及化實現之前,我想 AR 技術或許是最快實現類似體驗的方法吧? ( 配合 AR 眼鏡 )
DEMO VIDEO...
http://www.youtube.com/watch?v=W9s2ldmd9Vc
DEMO ONLINE...
http://www.asn.com.tw/flex/FlarMikuDemo/PV3DFlarTest.html
要線上執行需要列印出上列 Marker 檔,將其中的方塊組合起來,並且準備一台 Webcam,程式運行後再將 Webcam 對準方塊就會出現人偶嘍~(還有牛)!!!
Markers...
ARis Marker : http://www.asn.com.tw/flex/FlarMikuDemo/Data/ARisMarker.jpg
Cube Marker : http://www.asn.com.tw/flex/FlarMikuDemo/Data/CubeMarker.jpg
要自建 Marker 檔可以到…
http://flash.tarotaro.org/blog/2008/12/14/artoolkit-marker-generator-online-released/
======== 底下給有興趣寫 AR 程式的人作參考 ========
MultiMarker...
這個程式等於是 FLARToolKit 複數 Marker 的應用,在 FLARToolKit 中有個 FLARMultiMarkerDetector 的類別,是用來同時偵測多個 Marker 用的,MultiMarker 的偵測需要管理多個 Maeker 的 ARCode。
網路上有現成的多偵測點 Marker 管理函式庫 FLARManager…
這個 MultiMarker 管理類別功能蠻強大的,包含多點偵測、圖形二元化閥值最佳化、座標位置 smooth 及動態點預測…。
FlarDetetor...
不過我沒有實際去用 FLARManager,而是自己寫了個簡化版的 FlarDetetor,一樣是 MultiMarker Detect,還蠻好用的,我的 ARis 就是利用這個類別作出來的。
FlarDetetor 特色:
一、多個 Marker 同時偵測。
二、事件觸發 ( MARKER_ADDED、MARKER_UPDATED、MARKER_REMOVED )。
三、完全獨立的一個類別,低耦合,只用到原始的 FLARToolKit 類別。
四、俱備簡易 smooth 功能。
如何使用:
一、初始化,跟一般 FLARToolKit 應用程式一樣代入 FLARParam 跟 Webcam 的 Bitmapdata。
FlarDetector.init(_capture);
二、 建立 FlarObject 物件並載入 Marker 檔,然後加入 PV3D scene 中。
var cube:FlarCube = new FlarCube ();
cube.detector.loadCode( 'cube.pat',16,100 ); /// 注意後面二個 width 參數要與當初存 patern 時一致,否則測不出來唷。
this.scene.addChild( cube );
三、最後只要在 PV3D Render 的時候 detect 即可自動分派事件。
FlarDetector.detectMarkerLite();
FlarObject...
這個類別便是拿來裝你的 PV3D 子物件的容器,繼承自 FLARToolKit 的 FLARBaseNode 類別,並且有基本的一個 FlarDetector 及預設的事件反應,當 FlarDetector偵測到時便進行座標方位的轉換。
比較特別的地方在於我使用了一個 _pivot:DisplayObject3D 作為內容器,好方便底下延伸類別的座標軸轉換,所有子物件都放在 pivot中,就可以自由在程式控制相對位置跟方向,而不會受 Node Transform 的影響。
當然,其實 FlarDetector 是蠻低耦合的一個類別,你也可以直接使用 FlarDetector 在任何的場合,創造你自己的類別,也不一定要配合 PV3D 來使用,把 FlarDetector 當成一個單純的 Sensor 來使用即可。
FlarARisCube...
至於六面體 Marker 的偵測,網路上可以找到 Tarotaro 的 5 面立方體範例…
http://flash.tarotaro.org/blog/2009/04/06/cube-type-marker-in-flar/
他的演算法是將水平的四個面用二個 Marker 解決,一個偵測用,一個判斷面向用,再加上上面一個 Marker 總共三個,真聰明丫,詳細的演算法可以參考…
http://flash.tarotaro.org/blog/2009/06/10/about-cube-detection-algorithm/
但是可惜是這個方法只能作 5 面偵測,從底下往上看沒有(要幹嘛?!),而且水平的四個面的 Marker 必需有一定的規則,Marker 的設計要比較注意。
這 個函式庫我也沒實際去用,於是又寫了個 FlarARisCube 的類別,這個類別其實只是在一個類別中放了六個 FlarDetector,再在偵測到時轉換一下座標而己,只是在轉換座標時搞的有點暈頭轉向,我的方法是比較直接的方式,效能沒 Tarotaro 的好,只能說是比較容易實現的方法。
最後則是六面體方塊在上仰角度時,會有遮罩的效果,讓六面體看起來更直實(能遮到人偶),我是參考 FLARToolKit 的原作者 saqoosha 的這篇文章…
http://saqoosha.net/en/2009/01/08/1676/
文章是介紹地上打洞的效果,不過原理一樣 ( 地上打洞很酷丫,下回再來作 ^ ^ )。
Finally…
一連串的學習QQ",總算成功,出現人偶嘍~(還有牛)~呵呵呵。
Source Code...
原始程式下載:( 包含 papervision3d 及 flartoolkit )-原始版本
http://www.asn.com.tw/flex/FlarMikuDemo/FlarMikuDemo.zip
2009/12/22 - 最新的 source 改放在 google code,http://code.google.com/p/flardetector/
( 不包含 papervision3d 及 flartoolkit )
2009年12月10日星期四
Flartoolkits - Load DAE & Make your own Marker Online
在網路上即時載入 DAE 3D 模型,透過視訊即時的在線上建立 Flar 物件的 Marker。
操作方式:
1. Load DAE file,預設己經載入三個模組。
2. 下拉選單點選你要操作的FLAR物件。
3. 用麥克筆或印表機畫出你自訂的圖樣(正方形黑色邊框+裡面塗上簡易圖示)。
4. 按下 Detect Pattern,把視訊對準圖樣。
5. 當紅色標示出現在正確的位置時按下 Set Pattern。
6. 下方操控面板可以控制物件的大小及角度。
(亦可直接點選畫面上的物件操作)
DEMO VIDEO:
http://www.youtube.com/watch?v=Hp2qY4_Ez_Y
ONLINE DEMO:
http://www.asn.com.tw/flex/PV3DFlar/MarkerGeneratorOnline.html
操作方式:
1. Load DAE file,預設己經載入三個模組。
2. 下拉選單點選你要操作的FLAR物件。
3. 用麥克筆或印表機畫出你自訂的圖樣(正方形黑色邊框+裡面塗上簡易圖示)。
4. 按下 Detect Pattern,把視訊對準圖樣。
5. 當紅色標示出現在正確的位置時按下 Set Pattern。
6. 下方操控面板可以控制物件的大小及角度。
(亦可直接點選畫面上的物件操作)
DEMO VIDEO:
http://www.youtube.com/watch?v=Hp2qY4_Ez_Y
ONLINE DEMO:
http://www.asn.com.tw/flex/PV3DFlar/MarkerGeneratorOnline.html
2009年12月8日星期二
紅外線發射程式
最近用微處理器(MCU)寫了個紅外線發射的程式…
原本的想法太過於複雜,程式寫久了會想要把東西寫的更靈活,於是會自己加了很多動態的計算、即時的判斷程式碼,沒想到對系統資源有限、時序要求非常嚴苛的 MCU 卻是一種負擔,這在多核的MCU如FPPA下不是什麼大問題,但在傳統的 MCU 如 EMC 或 PIC 卻會讓你越靈活就越難以控制(尤其是當你用C而不用組合語言來寫的時候)。
在重新思考及嘗試後才發現原來程式很簡單…
/// 這邊的編碼是以 SM5032 為例…
void IR_Bit0( void )
{
/// 產生1/4週期的38KHZ載波
}
void IR_Bit1( void )
{
/// 產生3/4週期的38KHZ載波
}
void IR_Empty( void )
{
/// 空周期延時
}
void IR_Head( void ){
IR_Bit1();
IR_Bit1();
IR_Bit0();
}
void IR_Custom( void )
{
IR_Bit1();
IR_Bit1();
}
void IR_Tail( void )
{
IR_Empty();
IR_Empty();
IR_Empty();
IR_Empty();
}
#define _0 IR_Bit0();
#define _1 IR_Bit1();
#define _H IR_Head(); /// HEAD code
#define _C IR_Custom();/// Custom code
#define _T IR_Tail(); /// End code
void main()
{
Initial();
Initial_IO();
while(1)
{
if( BTN0 == 0 )
{
_H _C _0 _0 _0 _0 _0 _0 _1 _T
} else if( BTN1 == 0 )
{
_H _C _0 _0 _0 _0 _0 _1 _0 _T
} else if( BTN2 == 0 )
{
_H _C _0 _0 _0 _1 _0 _0 _0 _T
} else if( BTN3 == 0 )
{
_H _C _1 _0 _0 _0 _0 _1 _1 _T
} else if( BTN4 == 0 )
{
_H _C _0 _0 _0 _0 _1 _0 _0 _T
} else if( BTN5 == 0 )
{
_H _C _0 _0 _1 _0 _0 _0 _0 _T
} else if( BTN6 == 0 )
{
_H _C _0 _1 _0 _0 _0 _0 _0 _T
}
}
}
另外有一點要特別注意,一般紅外線發射會使用455KHZ的晶振,算是比較低頻,各家 MCU 特性不同,有可能會需要在 OSCO 串上個串聯電組 (5-10K)才會正常起振。
原本的想法太過於複雜,程式寫久了會想要把東西寫的更靈活,於是會自己加了很多動態的計算、即時的判斷程式碼,沒想到對系統資源有限、時序要求非常嚴苛的 MCU 卻是一種負擔,這在多核的MCU如FPPA下不是什麼大問題,但在傳統的 MCU 如 EMC 或 PIC 卻會讓你越靈活就越難以控制(尤其是當你用C而不用組合語言來寫的時候)。
在重新思考及嘗試後才發現原來程式很簡單…
/// 這邊的編碼是以 SM5032 為例…
void IR_Bit0( void )
{
/// 產生1/4週期的38KHZ載波
}
void IR_Bit1( void )
{
/// 產生3/4週期的38KHZ載波
}
void IR_Empty( void )
{
/// 空周期延時
}
void IR_Head( void ){
IR_Bit1();
IR_Bit1();
IR_Bit0();
}
void IR_Custom( void )
{
IR_Bit1();
IR_Bit1();
}
void IR_Tail( void )
{
IR_Empty();
IR_Empty();
IR_Empty();
IR_Empty();
}
#define _0 IR_Bit0();
#define _1 IR_Bit1();
#define _H IR_Head(); /// HEAD code
#define _C IR_Custom();/// Custom code
#define _T IR_Tail(); /// End code
void main()
{
Initial();
Initial_IO();
while(1)
{
if( BTN0 == 0 )
{
_H _C _0 _0 _0 _0 _0 _0 _1 _T
} else if( BTN1 == 0 )
{
_H _C _0 _0 _0 _0 _0 _1 _0 _T
} else if( BTN2 == 0 )
{
_H _C _0 _0 _0 _1 _0 _0 _0 _T
} else if( BTN3 == 0 )
{
_H _C _1 _0 _0 _0 _0 _1 _1 _T
} else if( BTN4 == 0 )
{
_H _C _0 _0 _0 _0 _1 _0 _0 _T
} else if( BTN5 == 0 )
{
_H _C _0 _0 _1 _0 _0 _0 _0 _T
} else if( BTN6 == 0 )
{
_H _C _0 _1 _0 _0 _0 _0 _0 _T
}
}
}
另外有一點要特別注意,一般紅外線發射會使用455KHZ的晶振,算是比較低頻,各家 MCU 特性不同,有可能會需要在 OSCO 串上個串聯電組 (5-10K)才會正常起振。
2009年12月6日星期日
有趣的 FLARToolKIT
結合 webcam 產生像是虛擬+實境融合的效果(Augmented Reality)~
http://blog.papervision3d.org/2009/01/07/augmented-reality-with-flartoolkit/
網路上有一大堆很酷的作品唷。
FLARToolKit 是一位日本人將 ARToolKit 改寫成 AS3版本,再配合 3D 引擎 (如 Papervision3D ) 作成的。
主要的原理是利用事先製作好的圖像(marker)作為辨識它在現實環境中的 3D 位置、角度…等等的資料,再套用到螢幕這個 marker 所代表的 3D 物件,結合 webcam 畫面就造成這樣的視覺效果了。
底下是自己練習的成果影片…
http://www.youtube.com/watch?v=tyQWHQH28iM
可以想像一下整個房間貼滿 marker 或 全身穿上有 marker 的衣服會是怎樣的情景~^ ^,有很多發揮創意的空間。
線上 Demo 在這…
http://www.asn.com.tw/flex/PV3DFlar/PV3DFlar.html
*要使用線上 Demo 必須準備 webcam,再列印我使用的二種 marker,到這個網址後會提示啟用 webcam,再把 marker 對著 webcam 鏡頭晃,就會在螢幕上看到效果了。
*我的 marker 可以在這下載。
http://blog.papervision3d.org/2009/01/07/augmented-reality-with-flartoolkit/
網路上有一大堆很酷的作品唷。
FLARToolKit 是一位日本人將 ARToolKit 改寫成 AS3版本,再配合 3D 引擎 (如 Papervision3D ) 作成的。
主要的原理是利用事先製作好的圖像(marker)作為辨識它在現實環境中的 3D 位置、角度…等等的資料,再套用到螢幕這個 marker 所代表的 3D 物件,結合 webcam 畫面就造成這樣的視覺效果了。
底下是自己練習的成果影片…
http://www.youtube.com/watch?v=tyQWHQH28iM
可以想像一下整個房間貼滿 marker 或 全身穿上有 marker 的衣服會是怎樣的情景~^ ^,有很多發揮創意的空間。
線上 Demo 在這…
http://www.asn.com.tw/flex/PV3DFlar/PV3DFlar.html
*要使用線上 Demo 必須準備 webcam,再列印我使用的二種 marker,到這個網址後會提示啟用 webcam,再把 marker 對著 webcam 鏡頭晃,就會在螢幕上看到效果了。
*我的 marker 可以在這下載。
2009年11月29日星期日
PV3D 練習 - Facebook 好友大頭照
DEMO:(需登入fb)
http://www.asn.com.tw/flex/20091129.htm
20110827更新連結…
http://www.vercenter.nknu.edu.tw/flex/FacebookFriends/LongfellowHelloFlex.html
在 facebook 上登入,讀取好友名單及大頭照,再將大頭照轉成 BitmapMaterial,用這個材質生成 PLANE,再置入 PV3D 場景中。
效果跟效能,並不是絕對的反比關係。
SOURCE:
package study
{
import game.FacebookAP;
import com.facebook.data.users.FacebookUser;
import flash.display.Bitmap;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BlurFilter;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import org.papervision3d.core.effects.view.ReflectionView;
import org.papervision3d.core.math.Quaternion;
import org.papervision3d.cameras.CameraType;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Plane;
public class study21 extends ReflectionView
{
private var currentQuat:Quaternion = new Quaternion();
private var targetQuat:Quaternion = new Quaternion();
private var slerp:Number = 0;
private var fbRadius:Number;
private var carousel:DisplayObject3D = new DisplayObject3D();
private var isMouseDown:Boolean;
private var fb:FacebookAP;
private var save_mouseX:Number;
private var save_rotationY:Number;
private static var planeWidth:Number = 50;
private static var planeHeight:Number = 50;
public function study21()
{
super(0,0,true,false,CameraType.FREE);
this.addEventListener(Event.ADDED_TO_STAGE, init0);
}
private function init0( event:Event ):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, init0);
fb = new FacebookAP();
fb.addEventListener( Event.COMPLETE, init1 );
fb.init();
}
private function init1( event:Event ):void
{
fb.removeEventListener( Event.COMPLETE, init1 );
opaqueBackground=0;
surfaceHeight = -5;
viewport.interactive=true;
viewportReflection.filters = [new BlurFilter(3,3,3)];
setReflectionColor(.7, .7, .7);
fbRadius = ( fb.friends.length * (planeWidth+planeWidth/2) )/(2*Math.PI);
camera.target = carousel;
camera.position = carousel.position;
camera.y = planeHeight/2;
camera.moveBackward( fbRadius+150 );
for( var i:int=0; i
{
var user:FacebookUser = fb.friends.getItemAt(i) as FacebookUser;
var lc:LoaderContext = new LoaderContext(true);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onLoadBitmap );
if( user.pic_square == "" )
loader.load(new URLRequest( "images/q_silhouette.gif" ), lc );
else
loader.load(new URLRequest( user.pic_square ), lc);
}
scene.addChild(carousel);
this.addEventListener(Event.ENTER_FRAME, onENTER_FRAME );
this.stage.addEventListener( MouseEvent.MOUSE_DOWN, onMOUSE_DOWN );
this.stage.addEventListener( MouseEvent.MOUSE_UP, onMOUSE_UP );
}
private function onLoadBitmap( event:Event ):void
{
var bodyMaterial:BitmapMaterial = new BitmapMaterial( Bitmap(LoaderInfo(event.target).content).bitmapData );
bodyMaterial.interactive=true;
bodyMaterial.doubleSided=true
var plane:DisplayObject3D = new Plane( bodyMaterial,planeWidth,planeHeight,1,1 );
plane.rotationY = ( 360 / fb.friends.length ) * carousel.numChildren;
plane.moveForward( fbRadius );
plane.y = planeHeight/2;
carousel.addChild(plane);
}
private function onMOUSE_DOWN(e:Event):void
{
isMouseDown = true;
save_mouseX = this.stage.mouseX;
save_rotationY = carousel.rotationY;
}
private function onMOUSE_UP(e:Event):void
{
isMouseDown = false;
}
private function onENTER_FRAME(e:Event):void
{
if( isMouseDown )
{
carousel.rotationY = save_rotationY + (180/Math.PI)*Math.atan((save_mouseX-this.stage.mouseX)/(fbRadius+150));
} else {
carousel.rotationY -= ( this.stage.mouseX - this.stage.stageWidth/2 )/200;
slerp += (1 - slerp) * .05;
var quat:Quaternion = Quaternion.slerp( currentQuat, targetQuat, slerp );
carousel.transform = quat.matrix;
}
singleRender();
}
}
}
http://www.asn.com.tw/flex/20091129.htm
20110827更新連結…
http://www.vercenter.nknu.edu.tw/flex/FacebookFriends/LongfellowHelloFlex.html
在 facebook 上登入,讀取好友名單及大頭照,再將大頭照轉成 BitmapMaterial,用這個材質生成 PLANE,再置入 PV3D 場景中。
效果跟效能,並不是絕對的反比關係。
SOURCE:
package study
{
import game.FacebookAP;
import com.facebook.data.users.FacebookUser;
import flash.display.Bitmap;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BlurFilter;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import org.papervision3d.core.effects.view.ReflectionView;
import org.papervision3d.core.math.Quaternion;
import org.papervision3d.cameras.CameraType;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Plane;
public class study21 extends ReflectionView
{
private var currentQuat:Quaternion = new Quaternion();
private var targetQuat:Quaternion = new Quaternion();
private var slerp:Number = 0;
private var fbRadius:Number;
private var carousel:DisplayObject3D = new DisplayObject3D();
private var isMouseDown:Boolean;
private var fb:FacebookAP;
private var save_mouseX:Number;
private var save_rotationY:Number;
private static var planeWidth:Number = 50;
private static var planeHeight:Number = 50;
public function study21()
{
super(0,0,true,false,CameraType.FREE);
this.addEventListener(Event.ADDED_TO_STAGE, init0);
}
private function init0( event:Event ):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, init0);
fb = new FacebookAP();
fb.addEventListener( Event.COMPLETE, init1 );
fb.init();
}
private function init1( event:Event ):void
{
fb.removeEventListener( Event.COMPLETE, init1 );
opaqueBackground=0;
surfaceHeight = -5;
viewport.interactive=true;
viewportReflection.filters = [new BlurFilter(3,3,3)];
setReflectionColor(.7, .7, .7);
fbRadius = ( fb.friends.length * (planeWidth+planeWidth/2) )/(2*Math.PI);
camera.target = carousel;
camera.position = carousel.position;
camera.y = planeHeight/2;
camera.moveBackward( fbRadius+150 );
for( var i:int=0; i
{
var user:FacebookUser = fb.friends.getItemAt(i) as FacebookUser;
var lc:LoaderContext = new LoaderContext(true);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onLoadBitmap );
if( user.pic_square == "" )
loader.load(new URLRequest( "images/q_silhouette.gif" ), lc );
else
loader.load(new URLRequest( user.pic_square ), lc);
}
scene.addChild(carousel);
this.addEventListener(Event.ENTER_FRAME, onENTER_FRAME );
this.stage.addEventListener( MouseEvent.MOUSE_DOWN, onMOUSE_DOWN );
this.stage.addEventListener( MouseEvent.MOUSE_UP, onMOUSE_UP );
}
private function onLoadBitmap( event:Event ):void
{
var bodyMaterial:BitmapMaterial = new BitmapMaterial( Bitmap(LoaderInfo(event.target).content).bitmapData );
bodyMaterial.interactive=true;
bodyMaterial.doubleSided=true
var plane:DisplayObject3D = new Plane( bodyMaterial,planeWidth,planeHeight,1,1 );
plane.rotationY = ( 360 / fb.friends.length ) * carousel.numChildren;
plane.moveForward( fbRadius );
plane.y = planeHeight/2;
carousel.addChild(plane);
}
private function onMOUSE_DOWN(e:Event):void
{
isMouseDown = true;
save_mouseX = this.stage.mouseX;
save_rotationY = carousel.rotationY;
}
private function onMOUSE_UP(e:Event):void
{
isMouseDown = false;
}
private function onENTER_FRAME(e:Event):void
{
if( isMouseDown )
{
carousel.rotationY = save_rotationY + (180/Math.PI)*Math.atan((save_mouseX-this.stage.mouseX)/(fbRadius+150));
} else {
carousel.rotationY -= ( this.stage.mouseX - this.stage.stageWidth/2 )/200;
slerp += (1 - slerp) * .05;
var quat:Quaternion = Quaternion.slerp( currentQuat, targetQuat, slerp );
carousel.transform = quat.matrix;
}
singleRender();
}
}
}
2009年11月27日星期五
PV3D 練習 - 加入影片
現在可以邊開車邊看電視了 ^ ^"
http://www.asn.com.tw/flex/cardrive/CarDriver4.html
20110827連結更新…
http://www.vercenter.nknu.edu.tw/flex/CarDriver/CarDriver.html
不過所使用的影片檔是伺服端的 flv 檔,若要使用外部的連結(如 youtube),則會有 security domain 的問題,還要再研究。
幾個問題要注意…
一、DAE 物件有可能是很多個小物件組成的,在 3DS 裡會有不同的名稱及材質名稱,若需要讓 DAE 物件能產生事件 ( 譬如這個例子中液晶電視的畫面會接收滑鼠按下的事件來停止、撥放影片 ),必須從讀入的 DAE 物件中抽取出子物件 ( getChildByName ),再把這個子物件加上 InteractiveScene3DEvent (材質亦需事先設定好 interactive = true,才能正確接收到事件。
二、同樣是 DAE 物件,由於物件的建立順序是先建立 DisplayObject3D 再 LOAD 進模型及上材質,因此在 Render 的時候要特別注意,別在還沒 FileLoadEvent.LOAD_COMPLETE 之前就先調用子物件 ( 例如本例中的車承軸及車輪 ),否則會誤用 NULL 物件。 解決的辦法是確認全部 LOAD 完再 startRendering 或者在每次使用前作 NULL check。
三、材質使用貼圖 bitmap 時要特別小心原 bitmap 的檔案大小也會嚴重影響到 render 的效能 ( 例如被我消去的草坪 = =",跟原本很大張的木箱圖 )。
PV3D 的效能確實不是很理想,但想必隨著 ADOBE 日後支援 3D 硬體 GPU 加速 (希望早點實現 ),PV3D (或其它 WEB 3D 引擎 ) 應該也會更讚才是,在此之前,先把效率最優化的技巧學好吧~ ^ ^
另外順便介紹一個超驚人的 Web 3D 引擎 UNITY,底下是官網 DEMO…
http://unity3d.com/gallery/live-demos/tropical-paradise
需要安裝個小小元件才能看到,不過效果驚人。
http://www.asn.com.tw/flex/cardrive/CarDriver4.html
20110827連結更新…
http://www.vercenter.nknu.edu.tw/flex/CarDriver/CarDriver.html
不過所使用的影片檔是伺服端的 flv 檔,若要使用外部的連結(如 youtube),則會有 security domain 的問題,還要再研究。
幾個問題要注意…
一、DAE 物件有可能是很多個小物件組成的,在 3DS 裡會有不同的名稱及材質名稱,若需要讓 DAE 物件能產生事件 ( 譬如這個例子中液晶電視的畫面會接收滑鼠按下的事件來停止、撥放影片 ),必須從讀入的 DAE 物件中抽取出子物件 ( getChildByName ),再把這個子物件加上 InteractiveScene3DEvent (材質亦需事先設定好 interactive = true,才能正確接收到事件。
二、同樣是 DAE 物件,由於物件的建立順序是先建立 DisplayObject3D 再 LOAD 進模型及上材質,因此在 Render 的時候要特別注意,別在還沒 FileLoadEvent.LOAD_COMPLETE 之前就先調用子物件 ( 例如本例中的車承軸及車輪 ),否則會誤用 NULL 物件。 解決的辦法是確認全部 LOAD 完再 startRendering 或者在每次使用前作 NULL check。
三、材質使用貼圖 bitmap 時要特別小心原 bitmap 的檔案大小也會嚴重影響到 render 的效能 ( 例如被我消去的草坪 = =",跟原本很大張的木箱圖 )。
PV3D 的效能確實不是很理想,但想必隨著 ADOBE 日後支援 3D 硬體 GPU 加速 (希望早點實現 ),PV3D (或其它 WEB 3D 引擎 ) 應該也會更讚才是,在此之前,先把效率最優化的技巧學好吧~ ^ ^
另外順便介紹一個超驚人的 Web 3D 引擎 UNITY,底下是官網 DEMO…
http://unity3d.com/gallery/live-demos/tropical-paradise
需要安裝個小小元件才能看到,不過效果驚人。
2009年11月26日星期四
PV3D 練習-幾種加入光影材質的方式
開車加入光影材質…
http://www.asn.com.tw/flex/cardrive/CarDriver3.html
幾種加入光影材質的方式…
在PV3D 裡面有所謂的 shadematerial,用來產生會按照光源反應出明暗變化的效果的材質,在使用上很方便,只需產生一個點光源,再利用它來 new 出一個 ShadeMaterial,再賦予物件使用。
最簡單的像是 org.papervision3d.materials.shadematerials 底下的 FlatShadeMaterial …
private function foo():void
{
var light:PointLight3D = new PointLight3D();
var shaderMaterial:FlatShadeMaterial = new FlatShadeMaterial( light, 0x123456, 0x000000 );
var plane:Plane = new Plane(shaderMaterial,500,500);
}
但有時會需要用貼圖的方式來生成物件的表面紋理,比較像真,這時要透過 shader 來重新製作俱備貼圖的 ShadedMaterial…
[Embed(source="assets/photo.jpg")]
private var bmpAsset:Class;
private function foo():void
{
var light:PointLight3D = new PointLight3D();
var yourBitmap:Bitmap = new bmpAsset() as Bitmap;
var bitmapMaterial:BitmapMaterial = new BitmapMaterial(yourBitmap.bitmapData);
var shader:FlatShader= new FlatShader( light, 0xffffff, 0x333333);
var shaderMaterial:ShadedMaterial = new ShadedMaterial(bitmapMaterial, shader);
plane = new Plane(shaderMaterial,500,500);
}
上面是靜態讀圖的作法,但是若是透過 BitmapFileMaterial 動態即時讀圖檔,卻會失敗…
private function foo():void
{
var fileMaterial:BitmapFileMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
/// after FileLoadEvent.LOAD_COMPLETE ....
var light:PointLight3D = new PointLight3D();
var shader:FlatShader = new FlatShader(light, 0xFFFFFF, 0x333333);
var shaderMaterial:ShadedMaterial = new ShadedMaterial(fileMaterial, shader);
var plane:Plane = new Plane(shaderMaterial,500,500);
}
因為 BitmapFileMaterial 並不是 BitmapMaterial 的子類別 ~"~,所以要稍微轉一下…
private function foo():void
{
var fileMaterial:BitmapFileMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
/// after FileLoadEvent.LOAD_COMPLETE ....
var light:PointLight3D = new PointLight3D();
var shader:FlatShader = new FlatShader(light, 0xFFFFFF, 0x333333);
var bitmapMaterial:BitmapMaterial = new BitmapMaterial( fileMaterial.bitmap );
var shaderMaterial:ShadedMaterial = new ShadedMaterial(bitmapMaterial, shader);
var plane:Plane = new Plane(shaderMaterial,500,500);
}
另外要注意,Cube 六面體若是要使用 ShadedMaterial 的話,六面都要 new 個新 shader 給它,否則會有三角形黑色塊產生 = =",很麻煩,而且跑起來非常秏效能。
org.papervision3d.materials.shader 底下還有很多種不同的 shader 可以使用,效果皆不同…
FlatShader
PhongShader
CellShader
EnvMapShader
GouraudShader
…
http://www.asn.com.tw/flex/cardrive/CarDriver3.html
幾種加入光影材質的方式…
在PV3D 裡面有所謂的 shadematerial,用來產生會按照光源反應出明暗變化的效果的材質,在使用上很方便,只需產生一個點光源,再利用它來 new 出一個 ShadeMaterial,再賦予物件使用。
最簡單的像是 org.papervision3d.materials.shadematerials 底下的 FlatShadeMaterial …
private function foo():void
{
var light:PointLight3D = new PointLight3D();
var shaderMaterial:FlatShadeMaterial = new FlatShadeMaterial( light, 0x123456, 0x000000 );
var plane:Plane = new Plane(shaderMaterial,500,500);
}
但有時會需要用貼圖的方式來生成物件的表面紋理,比較像真,這時要透過 shader 來重新製作俱備貼圖的 ShadedMaterial…
[Embed(source="assets/photo.jpg")]
private var bmpAsset:Class;
private function foo():void
{
var light:PointLight3D = new PointLight3D();
var yourBitmap:Bitmap = new bmpAsset() as Bitmap;
var bitmapMaterial:BitmapMaterial = new BitmapMaterial(yourBitmap.bitmapData);
var shader:FlatShader= new FlatShader( light, 0xffffff, 0x333333);
var shaderMaterial:ShadedMaterial = new ShadedMaterial(bitmapMaterial, shader);
plane = new Plane(shaderMaterial,500,500);
}
上面是靜態讀圖的作法,但是若是透過 BitmapFileMaterial 動態即時讀圖檔,卻會失敗…
private function foo():void
{
var fileMaterial:BitmapFileMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
/// after FileLoadEvent.LOAD_COMPLETE ....
var light:PointLight3D = new PointLight3D();
var shader:FlatShader = new FlatShader(light, 0xFFFFFF, 0x333333);
var shaderMaterial:ShadedMaterial = new ShadedMaterial(fileMaterial, shader);
var plane:Plane = new Plane(shaderMaterial,500,500);
}
因為 BitmapFileMaterial 並不是 BitmapMaterial 的子類別 ~"~,所以要稍微轉一下…
private function foo():void
{
var fileMaterial:BitmapFileMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
/// after FileLoadEvent.LOAD_COMPLETE ....
var light:PointLight3D = new PointLight3D();
var shader:FlatShader = new FlatShader(light, 0xFFFFFF, 0x333333);
var bitmapMaterial:BitmapMaterial = new BitmapMaterial( fileMaterial.bitmap );
var shaderMaterial:ShadedMaterial = new ShadedMaterial(bitmapMaterial, shader);
var plane:Plane = new Plane(shaderMaterial,500,500);
}
另外要注意,Cube 六面體若是要使用 ShadedMaterial 的話,六面都要 new 個新 shader 給它,否則會有三角形黑色塊產生 = =",很麻煩,而且跑起來非常秏效能。
org.papervision3d.materials.shader 底下還有很多種不同的 shader 可以使用,效果皆不同…
FlatShader
PhongShader
CellShader
EnvMapShader
GouraudShader
…
訂閱:
文章 (Atom)
