天天看點

CEGUI學習筆記七--如何擴充CEGUI控件庫(二)

本文是擴充CEGUI控件庫的第2部分,對FalButton.CPP檔案的分析記錄。

目的是探究下如何去控制 Renderer,進而徹底實作一個CEGUI沒有的控件類型。

但是分析未完成,希望這些半成品能對大家有用。

PS:由于公司的網絡限制,是以Blog很長時間未更新。家裡還沒電腦,上班偷偷寫的....

下次将整理下單獨編譯CEGUI,并給出CEGUI與Ogre結合的詳細步驟。

--------------------------------------------------------------------------------

//=====================================================================================================================

// 2008.4.18

//=====================================================================================================================

本來打算今天探究下如何去控制 Renderer,進而徹底實作一個CEGUI沒有的控件類型。

首先從FalButton開始切入,但是發現問題遠沒有想象中那麼簡單。

在先前對Falagard的翻譯中得知,如果要繪制一個控件,需要定義規定的StateImagery。

是以我期望在FalButton中看到這些狀态的集合,否則手冊裡規定的狀态從哪來呢?

實際上我看到的是 "Pushed" : "PushedOff"; "Disabled" "Hover"之類的 魔字元串!

現在知道這些狀态是哪來的了:在CEGUIfalagardWRBase項目裡相關檔案裡這樣定義的!這可真要命,太不可接受了。

OK,既然已經知道如何定義需要實作哪些狀态,再找找和顯示相關的代碼,在這個對象中,隻有一句跟這個相關:

wlf.getStateImagery(actualStateName(state)).render(*w);

1、wlf是WidgetLookFeel,

2、getStateImagery傳回StateImagery,

擷取WidgetLookFeel的唯一對象,然後得到一個叫actualStateName(state)的StateImagery,并調用它的render()方法來進行繪制。

以w為參數。w是什麼?

w是d_window,繼續查找這個成員變量,發現是WindowRenderer類的成員變量,回頭看H檔案的定義,FalButton繼承自WindowRenderer。

跟WindowRenderer類似的還有很多***Renderer的檔案,是以推測Button,Frame等簡單控件類型的繪制都繼承這個WindowRenderer。

而List等複合控件類型需要另外特别的***Renderer來實作繪制。

***Renderer裡實作繪制,确實是這樣的嗎?如果是這樣的話,為什麼要調用StateImagery對象的render()方法。

如果要繪制什麼東西,一定需要繪制它的參數資訊,包括資料和規則,既然***Renderer是作為參數傳遞給StateImagery的render(),

那麼***Renderer要麼給出了繪制方法,要麼給出資料,要麼給出規則。現在雖然不能确定,但是應該是提供規則的可能性大一些。

[後面将證明是錯誤的,它提供的不是規則而是資料。]

現在又有2條路了:

1、WindowRenderer是什麼東西。

2、StateImagery的render()到底做了什麼事。

先檢視WindowRenderer類的介紹:

// Base-class for the assignable WindowRenderer object

這是什麼,可支援的視窗渲染器對象的基類?顯然不太好對付。

從類視圖中可以看到它的派生類,找個複合控件,EditboxWindowRenderer類的介紹:

// Base class for the EditboxWindowRenderer class

OK,現在知道如果不看***Renderer的代碼的話,是不知道這個類做什麼用的了。

是以還是順着render()看。

有2個版本,但結構差不多,是以隻盯着一個看先。

先看這個函數的介紹,沒什麼很詳細的資訊....這說明如果我們了解整個設計目的的話,這個函數是理所當然的。

沒什麼好說的,RTFS。

void StateImagery::render(Window& srcWindow, const ColourRect* modcols, const Rect* clipper) const   

{

 float base_z;

 // render all layers defined for this state

 for(LayersList::const_iterator curr = d_layers.begin(); curr != d_layers.end(); ++curr)

 {

  // TODO: Magic number removal

  base_z = -0.0000001f * static_cast<float>((*curr).getLayerPriority());

  (*curr).render(srcWindow, base_z, modcols, clipper, d_clipToDisplay);

 }

}

又冒出很多新鮮玩意出來了,就知道!

LayersList?估計就是 XML裡的Layer關鍵字定義的那段東西,在CPP檔案裡的對應對象,暫時不管它的細節。

getLayerPriority?優先權?為什麼要和-0.0000001f相乘?請教老大之後得知,這個Z值是給3D渲染器用的。因為

getLayerPriority傳回的是整數,而3D渲染器的Z值是0到1,是以才需要這麼乘一下。

再看看 *cuur.render() 接受的參數:1個視窗的引用,1個Z值,1個頂點顔色矩形,一個裁減矩形,還有一個d_clipToDisplay?

bool d_clipToDisplay; //!< true if Imagery for this state should be clipped to the display instead of winodw (effectively, not clipped).

如果為true,就是相對于顯示器進行裁減,而不是視窗(實際上沒裁減)?

構造函數裡的初始化為d_clipToDisplay(false),搜尋操作這個變量的方法,發現跟XMLHelper扯上關系,

而整個CEGUI裡沒有調用這個方法來設定這個變量,看來是放出去給外部進行設定的,那就不管了先,等以後在某個例子裡發現的時候再回頭看。

好吧,現在繼續LayersList的render()。

 // render all sections in this layer

 for(SectionList::const_iterator curr = d_sections.begin(); curr != d_sections.end(); ++curr)

  (*curr).render(srcWindow, base_z, modcols, clipper, clipToDisplay);

又是個周遊,不過這次周遊的是SectionList。

再次回憶上次LookNFeel裡的定義:

StateImagery

 layer

  section = ImagerySection

而ImagerySection的層次是:

ImagerySection

 ImageryComponent

  Area

  Image

  VertFormat

那在這裡預測,如果查找(*curr).render(),一定是周遊一個ComponentList,然後調用 (*xx).render()。

不過找到的是擷取ImagerySection的代碼:

const ImagerySection* sect =

  &WidgetLookManager::getSingleton().getWidgetLook(d_owner).getImagerySection(d_sectionName);

然後sect->render(...);

結果與預測的不太一樣,在這個地方已經開始使用try和catch,說明已經開始實際的繪制操作,馬上就可以知道WindowRenderer提供

的到底是資料資訊,還是規則資訊了!

與預測不一樣的地方有2個:

1、擷取的不是Component,而是ImagerySection,為什麼?

2、沒有周遊,為什麼?

回頭檢視SectionList,

typedef std::vector<SectionSpecification> SectionList;

說明Layer裡可以有很多section,而section再來指出是哪個ImagerySection。是以應該先擷取ImagerySection。

而section和ImagerySection是1對1的關系,是以沒有周遊。

繼續看ImagerySection的render(...),在裡面發現了3個周遊:

FrameList:   FrameComponent   的render()

ImageryList: ImageryComponent 的render()

TextList:    TextComponent    的render()

FrameComponent   的render()裡進行了一大堆的計算,然後分别繪制了Frame的4個角、4條邊、1個背景。

雖然沒看,但估計其他2個差不多。這就是實際的繪制工作了!

現在回頭看看,Button有Frame嗎?之前寫Button的時候,隻寫了ImageryComponent。而我從FalButton開始切入,最後卻看到了

FrameComponent的繪制,這說明了什麼?

再從更大範圍上整理一下:

我在XML檔案裡定義 Button的渲染器 FalButton,

FalButton裡(通過d_window)判斷目前按鈕的狀态(現在對于***Renderer到底是個什麼還不清楚,等整理完就去看。),

再通過這個狀态來(通過WidgetLookFeel對象)得到對應的StateImagery對象。

然後調用StateImagery對象的render()方法,以*w為參數。

然而現在來看,從調用StateImagery對象的render()方法開始,已經跟Button沒關系了,一切都是按照規定好的流程在進行。

這說明如果我們要使用CEGUI的話,從這裡開始就是不變的東西,如果要改變的話,要做的事情就比較多了。

在這之前,我們能控制的(自由度)就是(添加或減少一個)控件狀态的定義。

但是在之前我寫Button1的時候,沒實作Hover狀态下的代碼,然後當我滑鼠移到Button1的時候,就沒圖檔顯示出來。

如果按這個流程的話,得不到StateImagery對象,就不會調用render,是以就沒圖檔顯示出來,這就說的通了。

今天就到這裡,下周順着WindowRenderer開始查。

本文來自CSDN部落格,轉載請标明出處:http://blog.csdn.net/kun1234567/archive/2008/04/25/2329483.aspx

繼續閱讀