2008年6月18日星期三

Resources loading

最近完成了漸進裝載系統 (Progressive resource loading) 的設計與實作.
現階段能夠以多緒形式載入 Jpeg 和 Png



要達到多緒, 首要分開載入和使用中的資料.
函式 load() 會把 istream 中的資料解碼到 loader 裏的私有緩衝區之中, 這時候 LoadingState 為 Loading.
當一定數量的資料已解碼而又可以顯示出來, load() 會返回 LoadingState = PartialLoaded, 這時候你可以乎叫 commit() 把 loader 中的緩衝抄到 resource 去.
請注意 load(), commit() 和 getLoadingState() 好有可能在不同的執行緒中執行, 因此 loader 裏的緩衝區和 LoadingState 成員都要用 Mutex 來保護.



有一點值得討論的就是 load() 這函式.
現在的設計須要用者不停地乎叫 load() 直到它返回 Loaded 或 Aborted. 但我曾經考慮過使用事件 (Event) 來通知用者現在的 LoadingState 從而只需乎叫 load() 一次. 接著當我試圖實作 cancel() 這函式時, 問題出現了; 我得建造另一個事件來控制 load() 內部的循環何時跳出.
實在不好, 複雜跳進來了...還要處理令人頭痛的多緒同步哩! 想起 Pull Xml 帶給我的啟示, 原來只要把 load() 內的循環交給用者來定義, 一切都簡單得多.
再細心的想, 如果用者希望一幅圖像載入了第一個漸進後便去開始載入另一幅圖像的話, 用事件的作法是行不通的 (或變得異常複雜). 所以這個新的設計不止簡單, 還非常靈活. 我又一次體會到什麼是 Less is more, There is No CODE that is more flexible than NO Code!.

2008年6月11日星期三

C++ friend class

有些時候我們會利用 C++ 中的 friend 關鍵字來設定類別的好友.
但可惜一個 friend 宣告只會對一個類別產生作用:

class Texture {
public:
friend class IResourceLoader;
uint width() const { return mWidth; }
uint height() const { return mHeight; }
private:
uint mWidth;
uint mHeight;
};

class IResourceLoader {};

class JpegLoader : public IResourceLoader {
void load() {
// ...
mTexture.mWidth = 128; // Compiler error!!
}
};

以上的 Texture 類別有成員 mWidth 和 mHeight, 它們都只應由 IResourceLoader 的實作類別所能更改. 幸好有 Inner class 可以幫到我們:

// Texture.h
class Texture {
public:
friend class IResourceLoader;
uint width() const { return mWidth; }
uint height() const { return mHeight; }

// We declare a templated inner class here (but not defined yet)
template class PrivateAccessor;

private:
uint mWidth;
uint mHeight;
};

class IResourceLoader {};

// JpegLoader.cpp
// Define Texture::PrivateAccessor here, access what ever you want
template<>
class Texture::PrivateAccessor {
public:
static size_t& width(Texture& texture) {
return texture.mWidth;
}
static size_t& height(Texture& texture) {
return texture.mHeight;
}
};
typedef Texture::PrivateAccessor Accessor;

void JpegLoader::load() {
// ...
Accessor::width(mTexture) = 128; // Ok! no problem
Accessor::height(mTexture) = 128;
}

你可能會認為這樣做等同把所有成員變為公開 (public), 事實上這個方案的精神在於迫使程序員清楚自己正在做什麼, 而不是錯誤地更改了變數.

Syntax highlighting

要貼原碼第一件事當然是設置"語法高亮度顯示" (Syntax highlight)
Syntaxhighlighter 是一個純粹用客戶端 Java Script 來達到效果.

還有一些文章 1, 2 有更好的指示.

2008年6月6日星期五

學習, 再學習

經過三年的遊戲引擎開發後, 縱然我從中已學到了許多; 但還要學的更多, 無窮無盡的多.
僅僅 C++ 這令人又愛又恨的東西我已學了十年 (Teach yourself programming in ten years).
那其實是一件好事, 我就是喜歡學習的過程.

華而不實的東西我已做過不少 (如 Exmat ).
現在我正集中焦點學習怎樣去設計簡單清晰的軟件.

而這裡正是用來把這過程記錄下來, 希望大家多多指教.