2011年7月29日 星期五

QCAR


昨晚在網絡上看新聞時,發現了一個擴增實境 SDK 免費供開發者使用。今天拿來一試,效果十分之好,效率亦十分之快!

了解過這個 SDK 後,使我對圖像辨認有新的了解。一直以來,我都是以類似 Histogram 之類的方法去編寫辨認圖像的程序;圖片必須要有一大塊的同色區域才能容易辨認。今次 QualComm 的 AR SDK 卻剛好相反;複雜的圖像反而更容易準確辨認。又給我上了一課!

2011年7月28日 星期四

DIY Segway

最近很想砌一架 DIY Segway 出來,搜集了一些資料:

My DIY Segway from Johannes Werum on Vimeo.


DIY Segway Test from Johannes Werum on Vimeo.




http://p1r.crf.nu/segway/

Linux 指令筆記

Note of Linux Commands

年紀大了,記性越來越差,很多事情用腦袋都記不住,要用網誌記錄:

為目錄加入密碼保護
首先用指令 htpasswd 建立密碼檔
/usr/local/apache/bin/htpasswd -c .htpasswd pacess

再用 vi 建立 .htaccess。內容如下:
AuthName "Pacess Only"
AuthType Basic
AuthUserFile /share/Qweb/folder/.htpasswd
require valid-user

搜尋檔案
find / -name 'htpasswd'

只顯示檔名
ls -m1

2011年7月27日 星期三

Windows 7 下擷取 YouTube 影片

Save YouTube Video in Windows 7

我轉用 Mac 已有三年時間,如沒必要都不會再使用 Microsoft 的產品。今次因為工作的緣故,需要把一條 YouTube 上的影片保留;而我不懂得在 Snow Leopard 的環境下是如何達成,於是只好求助於 Internet Explorer。

在 Windows 7 利用 I.E. 完整載入 YouTube 影片後,到 C:\Users\Administrator\AppData\Local\Microsoft\Windows\Temporary Internet Files 資料夾,以「上次存取日期」逆排;找出最大的檔案,把它拷到桌面;再把副檔名改為 .flv。完成!

2011年7月22日 星期五

陽光濾鏡

Sunlight Filter

最近的興趣是圖像處理,昨晚有空閒時間便左試試右試試。結果誤打誤撞之下製作了這樣的一個濾鏡。我稱它為「陽光濾鏡」。原因是這個濾鏡會生成一條條的光紋,就像烏雲散去時的柱光一樣;而且還帶點手繪畫的感覺,我十分喜愛這個效果。

2011年7月20日 星期三

Lion 隆重登場

Lion Online






Lion 剛剛在香港 Mac App Store 登場,我立即購買了。可能是太多人下載的緣故,花了 20 分鐘下下載完 3.9GB 的 Lion。正在 MacBook Air 上安裝,需時約 33 分鐘。Lion 下的 Safari 快了很多,爽。

2011年7月19日 星期二

WebSocket DEMO


經過兩天的修練,終於得成正果。WebSocket 能成功連線。原來 ws:// 是不用額外的設定;之前一直不能連線,是因為 IP 的問題。路由器的 Port 是設定好了,但 IP 用 localhost 是錯,應該是實體的 IP 才行。今次在研究之前,已為自己訂下一個小遊戲題材為藍本,這樣能針對實際情況來製作,可以學到很多原先估計以外的部份。對於這兩天的修練,我十分滿意。在 HTML5 方面的功力也增進了。不過,這個遊戲還需要點時間才能完成呢...。

2011年7月18日 星期一

WebScoket

今天整天都在研究 HTML5,其中一個技術是 WebSocket,能讓瀏覽器跟服務器緊密連線,是一個很實用的技術。可是搞了半天,仍然未能連線。相信是由於 ws:// 的緣故。我不知道要 ws:// 時該做哪些設定...。希望明天能搞定吧!

2011年7月16日 星期六

程序庫在裝置及模擬器下的設定

Static Library Settings for Both Device and Simulator

BeyondZ 開發了自己的靜態程序庫,以方便不同的專案使用;而程序庫會編譯成裝置版本及模擬器版本。在使用時經常只能編譯其中一個版本,十分麻煩。原來只要在 Targets 的 Library Search Path 中使用 $(PLATFORM_NAME) 的話,XCode 便會自動使用對應的裝置版本或模擬器版本。

2011年7月14日 星期四

觀看 PVR 圖檔

View PVR Image
今天發現了一個名叫「PvrUncrush」的小工具,能在 QuickLook 上看 PVR 格式的圖片。SF IV Volt 中的 PVR 圖檔也能用這個小工具觀看呢!
http://atpeek.download.atpurpose.com/PngUncrush.zip

下載後把檔案解壓,放到 /Library/QuickLook 下,重新登入或在 Terminal 輸入 qlmanage -r 即可。

2011年7月13日 星期三

小飛俠的 spr 檔案格式

SPR File Format in "Astroboy Tap Tap Rush"

今日找來 Astroboy Tap Tap Rush 來研究,發現內裡有一些 spr 檔案,應該是 Sprite 的意思,亦即是圖檔來也。用 HexEdit 一看,格式簡單易明。0-3 Bytes 是 spr 內有多少個 PNG 檔,之後的便是第一個檔的大小,接著是第一個檔的內容;第二個檔的大小,接著是第二個檔的內容...。我簡單地寫了一段程式,把 spr 內的 PNG 解放出來。得到的 PNG 完好無缺,可以作為參考之用。瞄了小飛俠的動作圖一眼,發現它的像素比例有點古怪,是縮小時的比例問題,好可能是拿家用機版本的圖縮小而成的緣故。

另外,之前用 iPhonePNGApp 解圖時會出現錯色或半解的問題,今天試了一個 Command line 的 iPhonePNG 來解小飛俠的 PNG,所有圖都能正常解開。
 //  Loading spr
NSString *directory = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"spr"];
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directory error:nil];

for (NSString *filename in array) {
NSString *fileExtension = [[filename pathExtension] lowercaseString];
if ([fileExtension isEqualToString:@"spr"] == NO) {continue;}

string = [directory stringByAppendingPathComponent:filename];
NSData *data = [NSData dataWithContentsOfFile:string];
unsigned char *dataBuffer = (unsigned char *)[data bytes];

unsigned int *headerInfo = (unsigned int *)dataBuffer;
unsigned int numberOfPNGs = headerInfo[0];

dataBuffer += 4;
for (int i=1; i<=numberOfPNGs; i++) {
headerInfo = (unsigned int *)dataBuffer;
unsigned int fileSize = headerInfo[0];
dataBuffer += 4;

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *outputFilename = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%02d.png", filename, i]];
NSData *singleData = [NSData dataWithBytes:dataBuffer length:fileSize];
[singleData writeToFile:outputFilename atomically:YES];

dataBuffer += fileSize;
}
}

2011年7月12日 星期二

Street Fighter IV Volt 的 obm 檔案格式

OBM File Format in "Street Fighter IV Volt"

有同事向我提出想了解「Street Fighter IV Volt」的製作方法;於是我嘗試解開內裡的圖檔,發現跟「THE KING OF FIGHTERS-i」一樣使用了很多 obm 格式的檔案。我不知道 obm 是不是某遊戲引擎的格式。我為「THE KING OF FIGHTERS-i」編寫了一個工具,能把 obm 轉換為 PNG 檔案,用在「Street Fighter IV Volt」一樣沒有問題,肯定了兩個遊戲的 obm 格式是一樣。

obm 還會分至少三個格式,以 2-3 Bytes 來分辨。其中一個格式在圖寬及圖闊數據後,是 512 Bytes 的色盤數據,往後的才是像素數據。以下是目前為止的代碼:
 NSString *directory = [[NSBundle mainBundle] bundlePath];
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directory error:nil];

for (NSString *filename in array) {
NSString *fileExtension = [[filename pathExtension] lowercaseString];
if ([fileExtension isEqualToString:@"obm"] == NO) {continue;}

string = [directory stringByAppendingPathComponent:filename];
NSData *data = [NSData dataWithContentsOfFile:string];
unsigned char *dataBuffer = (unsigned char *)[data bytes];
unsigned short *headerInfo = (unsigned short *)(dataBuffer);
unsigned short *palette = (unsigned short *)(dataBuffer+8);

int width = headerInfo[2];
int height = headerInfo[3];
unsigned char *imageBuffer = (unsigned char *)malloc((width*height)<<2);

int imageType = headerInfo[1];
switch (imageType) {
case 0x0801:
case 0x0804: {
int sourceOffset = 8+512;
int targetOffset = 0;

for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
unsigned char pixelByte = dataBuffer[sourceOffset];
unsigned short paletteValue = palette[pixelByte];

int alpha = (paletteValue&0x0001)<<7;
int blue = (paletteValue&0x003e)<<2;
int green = (paletteValue&0x07c0)>>3;
int red = (paletteValue&0xf800)>>8;

if (alpha != 0) {alpha = 255;}

// 0 = Blue
// 1 = Green
// 2 = Red
// 3 = Alpha
imageBuffer[targetOffset+0] = blue;
imageBuffer[targetOffset+1] = green;
imageBuffer[targetOffset+2] = red;
imageBuffer[targetOffset+3] = alpha;

targetOffset += 4;
sourceOffset++;
}
}
} break;

case 0x2001: {
memcpy(imageBuffer, palette, (width*height)<<2);

for (int i=0; i<(width*height)<<2; i+=4) {
unsigned char red = imageBuffer[i+0];
imageBuffer[i+0] = imageBuffer[i+2];
imageBuffer[i+2] = red;
}
} break;
}

image = [MainViewController raw2UIImage:imageBuffer width:width height:height];
[currentImageView setImage:image];
[currentImageView setFrame:CGRectMake(0, 0, width, height)];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
string = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", filename]];
[UIImagePNGRepresentation(image) writeToFile:string atomically:YES];
}

2011年7月11日 星期一

求兩點之間的角度

Get Degree of Two Points

Angle = Radians to degree( ATan2( differenceY, differenceX ))

2011年7月9日 星期六

THE KING OF FIGHTERS-i 的 obm 檔案格式

OBM File Format in "THE KING OF FIGHTERS-i"


得知「THE KING OF FIGHTERS-i」推出後真的很興奮。把 IPA 拿到手後,第一時間不是玩這個遊戲,而是想了解它的製作思路。爆開 IPA 後,發現很多 PNG 及 WAVE,還有很多 OBM。我選擇了一個細小的 obm,把它拉到 HexEdit 看看內裡的乾坤。

這個格式沒有任何加密,基本上一看就能分辨出 0-7 Bytes 是檔頭。當中 4-5 Bytes 是圖寬,6-7 Bytes 是圖闊,往後的都是像素數據。簡單地把 .obm 改名為 .raw,利用 Photoshop 便能打開。打開時只需要留意圖的寬闊值就可以,基本上都是 128, 256, 512 這些數,參考檔頭就知是那個數字。

2011年7月7日 星期四

關閉 Automatic Reference Counting

Disable Automatic Reference Counting

今天開了一個專案用來做編程的實驗,使用了習慣的寫法卻出現錯誤。原來是因為 XCode 4 加入了一項名為「Automatic Reference Counting」的東東。對於喜歡掌握大權的我,這些自動化的東西實在是一個障礙。要把它關閉,只要在 Project 的 Build Settings 找 Objective-C Automatic Reference Counting,把它設定為 No 即可。

2011年7月6日 星期三

拼湊 90 張卡圖片

Create 90 Cards by using Data Sets in Photoshop

在一個項目中,我們需要製作 90 張卡圖片,目標是 PNG 格式;一張卡是由卡背景圖、插圖及文字所組成。有點像 LFO 卡的格式。背景圖有 4 款,並以順排的形式使用,即 1, 2, 3, 4, 1, 2, 3, 4...。90 張插圖已經預先準備好。原本安排了三天時間給同事處理 90 張卡圖片,即是一天要處理 30 張,一小時要處理 3.75 張。換算起來 15 分鐘要完成一張是沒有難度。

不過,對於這樣像工廠式的工作,會覺得很悶之餘,效率也很低,而且出錯機會大。若遇上改動的話,又要重頭做起,實在不划算。這個情況在 U1 打工時,經常發生。尤其是那些 LFO 遊戲卡。很多時候會作出大改動,實在浪費資源。所以當時我曾在 Illustrator 引入 DataSet 流程以加快效率。今次則在 PhotoShop 中引入,效果十分之好。

首先是建立範本。底層是卡圖、中層是插圖、頂層是文字。之後在 Image > Variables > Define 中加入各層的變量名稱。我的習慣是做用圖層名作為變量名稱,並且設定置換方或。這時範本已經完成。接著建立一個純文字檔,第一行是變量名稱,以逗號分隔。如:Background, Picture, Text。第二行開始便是數據。

有了範本及數據之後,便是合併的時候。在 Image > Variables > Data Sets。按 Import 並選包含數據的文字檔。如格式正確的話,數據便已經載入。若要把每個數據輸出成獨立 PSD 檔,可以點 File > Export > Data Sets as Files。


由於要準備 90 張卡片的數據也要點時間,所以用了點技巧加速。其中一項是取得檔名的方法:

1) 打開 Terminal
2) 跳轉到目的資料夾
3) ls -m1 > filelist.txt

2011年7月4日 星期一

UTF-8 檔頭

UTF-8 Header

最近在一個項目中,會從 PHP 中輸出包含 UTF-8 內容的 CSV 檔案。可是在 Excel 中打開 CSV 時,會出現亂碼。原因是欠缺了 UTF-8 應有的檔頭。修正方法如下:
 $fileHandle = fopen("debug.txt", "wb");
$headerWithContent = "\xEF\xBB\xBF".$fileContent;
fputs($fileHandle, $headerWithContent);
fclose($fileHandle);

2011年7月2日 星期六

訪問兩年後...

2 Years Later of the Interview...

兩年前,我接受了《南華早報》記者的訪問。兩年後的今天,我重新檢視一遍,發現當中的兩個目標已經完成了一個,另一個希望也能在兩年內發生吧!加油!