最後的一個條件
June 21, 2009 – 8:52 am拿沙特工資,
住英國房子,
用芬蘭手機,
戴瑞士手表,
娶韓國女人,
看日本AV,
做泰國按摩,
開德國轎車,
坐美國飛機,
喝法國紅酒,
吃澳洲海鮮,
抽古巴雪茄,
穿意大利皮鞋,
玩西班女郎,
看奧地利歌劇,
買俄羅斯別墅,
雇菲律賓女佣,
配以色列保鑣,
洗土耳其桑拿,
………..
當中國干部!!!
我的Coding 求生筆記
拿沙特工資,
住英國房子,
用芬蘭手機,
戴瑞士手表,
娶韓國女人,
看日本AV,
做泰國按摩,
開德國轎車,
坐美國飛機,
喝法國紅酒,
吃澳洲海鮮,
抽古巴雪茄,
穿意大利皮鞋,
玩西班女郎,
看奧地利歌劇,
買俄羅斯別墅,
雇菲律賓女佣,
配以色列保鑣,
洗土耳其桑拿,
………..
當中國干部!!!
最近在寫一個新的open source project。
理想中,應該是dual license 的,non-commercial use 是GPL,commercial的,就要收點錢 :)
一如過往,先來幾張圖:
這到底是什麼東西呀 ??
我也不知道呢 :)
應該是畢卡索在學習flash 時亂畫一通的作品。(大笑)
不過它包括了以下東西:
1. Radial Gradient.
2. Linear Gradient.
3. Shape Drawing <- this is the hard part!!!
4. Jpeg loading and drawing.
5. Frames control (可惜我還是不懂cap video…)
暫時是以SDL為rendering engine,不過我只是 memcpy 了一段 raw memory 去SDL_Screen,
所以簡單一點說,是render api independent 的。
可惜還有慢慢長路….
待開發得完整一些再談吧 : )
剛看完了google wave 的 preview 簡單一點講,就是過份!!
集 wiki , im, email, discussion group, bbs, blogging , micro-blogging 於一身的工具!
還要支援 cooperating editing !!
還是天生的open source + open protocol !!!
這不就是傳說中的”攞你命三千”???
記著,有錢,一定要買google 的股票!!!
剛剛看到日子,有一年零四日沒有更新.. :)
最近看到同事和朋友的Blog中,大家也在開發自家的遊戲引擎,心想不如我也參與其中吧。
而且,發覺自己真的開始老了,寫程式的進度很慢很慢,或許是時候自我進修一下。
所以…. 好,去片:(我還不懂Cap 片..)
From |
內容只是十分簡單,不過實作了三樣想寫很久的東西:
1. Lua based framework with coroutines
Lua 最最強大的地方是,實入了coroutines。由於在實際上寫script 的人,多數是game designer,
Event driven based 的script system對他們來說是比較有一點難度。
但若引入了Coroutines,Script 的編寫就會變得直線很多:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | -- Create an window Window { title = "Lua Framework", x = 30, y = 30, w = 800, h = 600, fullscreen = true } -- Create the camera Camera { eye = {-5.0,5.0,1.0}, target = {0.0, 0.0, 0.0}, } --Create Objects objects = {} r = 5.0 n = 10 for i=1,n do local theta = ((2.0 * math.pi) / n ) * i; if i < 4 then objects[i] = Object { Movable(), Renderable(geom.cube, 2.0) } elseif i < 7 then objects[i] = Object { Movable(), Renderable(geom.sphere, 1.0, 20), } else objects[i] = Object { Movable(), Renderable("teapot.obj") } end objects[i].movable.position = { math.sin(theta) * r, 1.0, math.cos(theta) * r, } objects[i].movable.orientation = { 0, 1, 0, theta + (math.pi * 0.5), } end offset = 0 -- start our main game loop while true do -- tell the system to we are idle, to let system do its work idle() for k, v in pairs(teapots) do local theta = ((math.pi * 2.0) / #objects) * k + offset; v.movable.position = { math.sin(theta) * r, math.sin(theta) * math.cos(theta) * r, math.cos(theta) * r, } v.movable.orientation = { 0, 1, 0, theta + (math.pi * 0.5), } end offset = offset + 0.001 p1 = objects[1].movable.position p2 = objects[2].movable.position -- Print some text on screen print(string.format("%f,%f,%f, %f,%f,%f", p1[1], p1[2], p1[3], p2[1], p2[2], p2[3], #objects)) end |
以上是一個簡單的script ,只是會看到幾個Box, Sphere 和 Teapot 在移動。
但特別的地方是那個 idle() ,它是一個coroutine ,會把Lua 的運行suspened了,把運行的權利交會給system,
直至system 呼叫 lua_resume 這個 C Api 。
2. No C++, Only C
原因有很多,最簡單的原因是,compile 的時間快了十倍 :)
3. Meshless Deformations Based on Shape Matching
幾年前看到了它的demo後,便很想把它實作出來,
而由於我想開發的新遊戲,需要有一個deformable 的physic engine,所以便試它一下。
暫時只實在了Linear Deformation,和沒有 object to object collision ,
不過還是很好玩 :)
最後,原本想upload 那個demos上來,但不知道為什麼,upload 不了,
等我問問橙先生後,再放上來 :)
最近在計畫編寫一個Assets Management Tools,所以在想這樣的工具,最好的編寫工具是什麼。我理想中的結構是由多個不同的工具所組成,其中之一個是Web介面。
所以就試用了一下Django,跟了它的幾個example寫了一下。實在是設計得很好。由其是它的MTV(Model-Template-View)式的設計,實在夠方便。
但是有一點,是我完全不明白它是如何做得到的:
1 2 3 4 5 6 7 8 9 10 | from django.db import models # Create your models here. class Publisher(models.Model): name = models.CharField(maxlength=30) address = models.CharField(maxlength=50) city = models.CharField(maxlength=60) state_province = models.CharField(maxlength=30) country = models.CharField(maxlength=50) website = models.URLField() |
這個是Models.py 中定義的Model,django會自動找出所有在這裡被定義的class,再把它們變成相對應的SQL statements,之後把它們create 出來。
我不明白的是,它怎麼能自動找出來呢???我最多只是import 了這個py 檔案,但又沒有把每個class instantiate 出來…
要知道,只好用最後一招,看source code!!!經過一番找尋,終於搞明白了,它用了一個C++ coder 不會用到的meta-programming 的技巧:
1 2 3 4 5 6 7 8 9 | class ModelBase(type): def __new__(cls): .... ..... return register_model(cls); class Model(object): __metaclass__ = ModelBase |
在這裡,__metaclass__是指Model的meta class。
那原本Model的Meta class 是什麼呢? Model 是一個type,所以就是type 啦。
上面的代碼,就是把Model 的Meta Class override,之後定義了一個__new__的方法,當每次Create這個metaclass是也會被call,就在這個時候,register_model就會把這個class 存起。
那什麼時候,這個metaclass 會被Create 呢??就是在定義它自己,和它的sub class時。留意,是定義時,所以當python import 了models.py 時,它就會create Publisher這個Class (是Class,不是Instance),由於Publisher 是Model的sub class,所以,ModelBase 這個metaclass 就被Create了。
有點頭昏了,對嗎??我看到這裡,真的覺得,Python 的 Meta-Programming真的很強大,強大得也太深奧了,怎麼可以一時三刻理解呢???不過也証明coding的世界是這樣大,實在有太多有趣的地方可以去玩玩看:)
amop 是我所寫的一個C++ Mock Object1 Framework,它是開源2的,也是我第一個開源的程式。
在我開發這個程式之前,我也是使用其他人所寫的Mock Object Framework,但使用起來,發覺有一點麻煩:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class Interface { virtual ~Interface(){}; virtual void Foo() = 0; }; class BaseMock : class Interface, MockObject { virtual void Foo() { // Check this function is called } } ... BaseMock mockObject; ... // Some way to call the Interface::Foo mockObject.Foo(); mockObject.Verify(); |
這種方法的麻煩,在於每一個你要測試的介面3,你也要繼承出一個BaseMock,而且,當你改變了那個介面:
1 2 3 4 5 6 | class Interface { virtual ~Interface(){}; virtual void Foo() = 0; virtual void Bar() = 0; }; |
你就得為每個BaseMock類別加上新的Bar 實作4。
所以,我在想,若果能不需要那BaseMock就太好了。但想了很久也想不出方法,所以就不了了之了…
但這個問題在腦中不斷的出現,最後,想到了一個正常被禁止的方法5:
直接改動C++ 的virtual table
為什麼這個方法是被禁止?因為virtual table 的 ABI 6,對每個編譯器也會有不同的實作方式,所以肯定是不能跨編譯器7的。但實在是想不到其他方法後,我就開始試寫出來。
除了ABI 之外, 最大的問題是有大量template meta-programming,我差不多用了我一生所學,有關C++ template 的技巧也用上了。8,所以花了很長的時間才完成。完成後,就給了它一個名字:
Automatic Mock Object For C plus plus
AMOP,我的開源兒子,就在google code 出世了。
還以為一個不能跨編譯器的Library,不會太多人使用9,但它的下載數字,卻在不斷增加。在討論頁中的討論,也已經很長了:)
最開心的是,人們的反應:
“Hi very nice framework!!! This can be the leading mock framework for c++. ”
“Very, very good framework! We are using in ourcompany to make our Unit Tests easier and more robust. Congratulations. Very nice work !”
“Nice framework!”
“Hi, really like what I’m seeing. Great idea to use the ABI. Obvious and genius at the same time. ”
我編寫程式也很多年了,但從來沒有給別人說過,我寫的程式是 “very nice framework”。很多時候,在商業上,其他公司會要求給出一些他們的應用程式的好評,但多數也不是真心話,但Amop 這些評語,是在沒有利益關係下,在互聯網上的不知名的人給出的,他們用不著對我說假話。
我想,這就是為什麼,在沒有利益的情況下,有那麼多人會去寫開源軟件了。所以,希望你看到我這些說話後,也來寫寫開源軟件,不為利益,為快樂而寫程式 :)
假如要寫出以下的Macro1:
1 2 3 4 | #define SWAP(a, b) \
temp = (a); \
(a) = (b); \
(b) = temp; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | float temp; float a = 10; float b = 20; // case 1 SWAP(a,b); // Correct. // case 2 if( a > 10) { SWAP(a,b); // (2) Correct too, } // case 3 if( b > 10) SWAP(a,b); // Fail !!! |
因為Case 3中的Macro,會被轉化為:
1 2 3 4 | if( b > 10) temp = (a); (a) = (b); (b) = temp;; |
這明顯不是我們想要的結果,所以就出現了這個小技巧:
1 2 3 4 5 6 | #define SWAP(a, b) \
do { \
temp = (a); \
(a) = (b); \
(b) = temp; \
} while(false) |
這樣定義SWAP這個Macro,問題就解決了,就算在Case 3的情況下,也會被轉化為:
1 2 3 4 5 6 7 8 | if( b > 10) do { temp = (a); (a) = (b); (b) = temp; } while(false); |
很簡單的小技巧,不過若不懂,就要想很久了:)
有一些 C 的語法,在 C++ 的程序員相對少用。但就是因為這個原因,有時就會忽略了。
假設我們有一個Header檔 Foo.h:
1 2 3 4 5 6 7 8 9 10 | static void f1() { std::cout << "f1()" << std::endl; } void f2() { std::cout << "f2()" << std::endl; } |
f1 和 f2 的分別在於 static 這個 keyword 。在這裡的 f1 被宣告和定義(declare)1為 static ,是指它只在這個Compilation Unit中生效。而 f2 沒有被定義為 static ,亦即是它可以被其他 Compilation Unit 訪問。
但到底什麼是 Compilation Unit呢?? 首先,一個程式編譯過程如下:
這裡的 a.cpp , b.cpp 和 c.cpp 也 引入2了Foo.h 這個檔案,經過預處理器3後,Foo.h的內容會被加入到 a.cpp, b.cpp 和 c.cpp 中,再經過編譯器4,變成為 a.o , b.o 和 c.o 這些目的碼5,最後經過連結器6,變成執行檔7。
要留意的地方是,每個經過預處理器處理後的.cpp 檔,和它的目的檔是一一對應的,而Compilation Unit,就是這些被處理後的.cpp 檔了。
若以Foo.h 的 f1 為例子,雖然在每個 .cpp 檔也被定義了,但經過編譯後,所有的f1 也會被隱藏在自己的目的檔中,連結器在找尋symbol的過程中,是會忽略的。
但f2 就不同了,所有的f2 在目的檔中,也是不會被隱藏,所以在連結器找尋symbol,會找到多份的f2,那就會有連結器錯誤8 了。
所以在大部份的情況下,在Header檔中定義函數9,也是需要static 這個keyword 的。就算加上了inline,情況也是一樣的。
1 2 3 4 | static inline void f3() { std::cout << "f3() is called" << std::endl; } |
作為一個C++程序員,C++ 這語言本身的認識,是很重要的。有時,有一些語法和守則,因為太少接觸和應用,所以會完全忽略了。希望這個C++ 求生筆記系列,可以給大家參考和交流一下。
今天先說一下這個keyword:template,一個簡單的使用如下:
1 2 3 4 5 6 7 8 9 10 11 12 | template < typename T > class Foo { public: template <typename R> R Func() { return R(); } }; |
這一段程序定義了一個Template1 Class和一個Template Function,以下是使用它時的代碼:
1 2 | Foo<int> foo; foo.Func<float>(); |
實例化(instantiate)了Foo,再實例化了Func,很簡單,對吧。
另一個使用template的時候,是比較少用到的 template template parameter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | template < typename T , template <class S> class C > class Bar { public: C<T> Func() { return C<T>(); } }; Bar<int, Foo> bar; bar.Func(); // Should return a Foo<int> Object |
Bar 以一個typename 和一個 template Class 作為它的template 參數,在此例子中就是int和我們之前定義的Foo。所以,Bar::Func的返回值,就是Foo<int>。這個應用其實不難看到的,在一些講解C++ Template 的書中也有提及。
最後我想講的是這個:
1 2 3 4 5 6 7 8 9 10 11 12 13 | template <class T, template <class S> class C > class Blah { public: T Func() { // Calling Foo<int>::Func<int> return C<T>().template Func<T>(); } }; Blah<int, Foo> blah; blah.Func(); |
和Bar 一樣,C
1 | C<T>().template Func<T>() |
就是去呼叫(call) Foo<int>::Func<int>,但為什麼要加上template 呢??2,因為在編譯器角度,Func可以是類型(Type),可以是變數(Variable),也可以是其他東西,它需要知道它是什麼才可以正確編譯3。所以就有了keyword template 的這種用法了4。
有時我覺得,C++真的很博大精深,經常會想到一句名句:「知道得越多,就會知道得越少!」