• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            的筆記

            隨時(shí)隨地編輯

            BLENDER架構(gòu)

             

            BLENDER架構(gòu)

             

            原文:http://www.blender.org/development/architecture/

            此文并非嚴(yán)格的學(xué)術(shù)翻譯,有錯(cuò)誤的地方請(qǐng)指出,一些非技術(shù)性的東西可能被刪節(jié)了。交流學(xué)習(xí)聯(lián)系方式:

            Kuafu:augustus4400(at)gmail(dot)com

            Blog:http://www.shnenglu.com/flyindark/



            簡介

            在過去的8Blender的代碼庫一直在發(fā)生變化,并且擴(kuò)大了很多。(刪除了本段后續(xù)部分)

             

            在這份文檔中我將目標(biāo)集中在回顧當(dāng)初原始的設(shè)計(jì)理念上,例如這一部分是如何實(shí)現(xiàn)的,或這部分實(shí)現(xiàn)對(duì)應(yīng)代碼樹里哪一處。既然下面即將介紹的原始設(shè)計(jì)理念可以很好的工作到現(xiàn)在,那么這個(gè)信息對(duì)當(dāng)前所有的開發(fā)工作都會(huì)有益處。

             

            本文檔的第二個(gè)目的是提供Hooks,以方便我們可以更深入的使用'模塊化的BLENDER

             

            BLENDER的設(shè)計(jì)的好壞是另外一個(gè)話題!特別是(角色)動(dòng)畫系統(tǒng)的知識(shí)沒有出現(xiàn)在最初的設(shè)計(jì)階段,這也是為什么Armatures、約束和NLA在現(xiàn)在仍然有問題的原因。另一個(gè)方面是當(dāng)初為趕時(shí)間,游戲引擎和邏輯編輯在后來才加入,這些地方與BLEDER也沒有很完美的協(xié)調(diào)工作。

             

            雖然這兩個(gè)方面都可以在當(dāng)前的設(shè)計(jì)中進(jìn)行改進(jìn),但我們最好還是承認(rèn)BLENDER存在一些短處。在現(xiàn)在這個(gè)框架上改進(jìn)功能和優(yōu)化結(jié)構(gòu)仍然是可能的,其中最有可能的是最終的代碼可以集中在完全重構(gòu)的Blender3的框架和模塊化中完成改進(jìn)。同樣這也是另外一個(gè)話題。讓我們先試圖將這個(gè)瘋狂的野獸控制住.:)

            所見即所想;所做即所得

            Blender最初是在動(dòng)畫工作室中開發(fā)的,符合它自己的用戶所需求,作為一個(gè)商業(yè)軟件按照工作進(jìn)度和截止日期完成開發(fā)。(意譯)

             

            它有一個(gè)嚴(yán)格的面向數(shù)據(jù)的設(shè)計(jì)方式,幾乎像一個(gè)數(shù)據(jù)庫,但也有一些面向?qū)ο蟮乃枷搿K耆杉?span>C編寫。為了設(shè)計(jì)Blender,有一種嘗試是建立一個(gè)盡可能統(tǒng)一的數(shù)據(jù)結(jié)構(gòu),來實(shí)現(xiàn)3D展現(xiàn)的所有可能性和所有通用的工具。

             

            這個(gè)結(jié)構(gòu)是為了讓用戶和程序員能夠迅速和靈活,這是一個(gè)非常適合開發(fā)室內(nèi)3D和動(dòng)畫包的工作方式。

             

            雖然有些戲稱Blender'結(jié)構(gòu)可視化',但是這個(gè)名字其實(shí)是相當(dāng)準(zhǔn)確的。在第一個(gè)月的Blender的開發(fā)中,我們除了設(shè)計(jì)框架和編寫包含文件確實(shí)做的不多。在隨后的幾年里,主要的工具和可視化的方法逐步完成。

             

            此圖描述了Blender最基本的結(jié)構(gòu)。“數(shù)據(jù)---可視化---編輯”這個(gè)循環(huán)周期是它的核心,并被GUI(圖中藍(lán)色處)分隔開來,GUI3個(gè)不同的層次工作。

             

            Data Select

            一個(gè)用戶選擇'數(shù)據(jù)'。這意味著用戶指定他希望工作的那部分三維數(shù)據(jù)庫。這是一樹狀結(jié)構(gòu)的組織。Blender的基本數(shù)據(jù)系統(tǒng)存在于文件上,這個(gè)數(shù)據(jù)系統(tǒng)直接和它加載到內(nèi)存中的映射是一致的。Blender數(shù)據(jù)可以包含多個(gè)'scenes',每個(gè)場景輪流的由3D Objectsmaterials,動(dòng)畫和渲染設(shè)置組成。

             

            Visua Select(visua or visual?)

            指定的數(shù)據(jù)可以在Windows作為三維線框通過Zbuffer渲染來顯示,如按鈕或一個(gè)示意圖。Blender有一個(gè)柔性的windows系統(tǒng)實(shí)現(xiàn)這個(gè)目標(biāo),這個(gè)窗口系統(tǒng)允許任何非重疊和非阻塞型的窗口布局體系。

             

            Edit Select

            根據(jù)可視化的選擇,用戶可以使用很多工具。編輯操作總是直接作用于數(shù)據(jù),而不是數(shù)據(jù)的可視化。這似乎是合乎邏輯的,但這是很多軟件的交互性和視覺方面的失敗。一方面它是一個(gè)速度問題,在三維可視化時(shí),它需要一定的時(shí)間后用戶才看能到一個(gè)編輯命令的作用。這也是一個(gè)'反矯正的問題:用戶只是了解可視化,而不是實(shí)際描述的數(shù)據(jù)結(jié)構(gòu)。這可能非常痛苦,如果你試圖做一些事情,結(jié)果最終被證明所做的與你想要的正好相反。

             

            UI design decisions (本節(jié)未翻譯,覺得原文更好理解)

            With a 3D creation suite requiring many different but conceivable methods to make the complexity available for artists, most programs ended up with providing multiple modules, separating the workflow for artists based on tasks like 'animating' or 'material editing' or 'modeling'.

             

            Based on our experience, as an animation studio, we didn't think this was natural nor followed the actual workflow of an art project.

             

            Following the flow diagram as mentioned above, decided was to:

            1. Base the UI on a non-overlapping non-blocking subdivision window system

            2. Allow each subdivided 'window' in Blender to be hooked up with any 'editor' (= vizualization method), displaying any choosen type of data.

            3. Implement a uniform usage of hotkey and mouse commands, that don't change meaning within different contexts.

            4. Since it's an in-house tool, speed of usage had preference over ease of learning

            The implementation of the UI was first tried with existing tools (libraries), but that failed completely because of lack of speed. The choice to create an entire new window manager, and base it all on IrisGL (predecessor of OpenGL), was one of the happy coincidences that made Blender as portable and slim as still is today.

             

            數(shù)據(jù)結(jié)構(gòu)

            Blender設(shè)計(jì)的大部分時(shí)間用于決定哪些類型的數(shù)據(jù)類型要定義在一起,以及如何定義數(shù)據(jù)之間的關(guān)系。在時(shí)刻記住“'實(shí)現(xiàn)遵循設(shè)計(jì)”的理念的前提下,任何設(shè)計(jì)決策既有效又盡可能功能約束是很好理解的。

             

            根據(jù)我們?nèi)绾涡枰?span>3D來實(shí)現(xiàn)我們的項(xiàng)目,做出了數(shù)據(jù)設(shè)計(jì)的決策,實(shí)現(xiàn)了一個(gè)高度抽象的數(shù)據(jù)層:

             

            - 允許多人協(xié)同工作

            - 讓復(fù)雜的動(dòng)畫項(xiàng)目建立在1個(gè)項(xiàng)目(或文件)的基礎(chǔ)上

            - 允許高效的重復(fù)使用的數(shù)據(jù)

            - 允許模板(或背景)

             

            這導(dǎo)致設(shè)計(jì)一個(gè)非標(biāo)'數(shù)據(jù)庫',不像傳統(tǒng)的'場景圖'(這在當(dāng)時(shí)基于的概念/顯示),而是基于創(chuàng)建通用的3D的數(shù)據(jù)世界,在那里你可以創(chuàng)建你想要的足夠多的場景圖(顯示,圖像,動(dòng)畫等)。

             

            順便說一句:認(rèn)識(shí)這個(gè)數(shù)據(jù)結(jié)構(gòu)的概念一直是新用戶進(jìn)入Blender的瓶頸:)

             

            Blender數(shù)據(jù)塊是用戶的積木:它們可以隨心所欲的被復(fù)制,修改和與另一塊建立鏈接。

             

            創(chuàng)建一個(gè)鏈接實(shí)際上和指明關(guān)系是一樣的。這會(huì)導(dǎo)致一個(gè)塊'被使用'。這可能會(huì)產(chǎn)生一個(gè)塊的實(shí)例,或者得到一個(gè)特定的特征(類似C++中特化的概率?)

             

            For example, the block type 'Object' makes a 'Mesh' block appear in the 3d scene. The Object here determines the exact location, rotation and size of the Mesh. The Mesh then only stores information on vertex locations and faces. Also, more than one Object can have a link to the same Mesh (use, create an instance). Other block types, e.g. Materials, can be linked to Meshes to obtain the block type's features.

             

            Blender中每一個(gè)這樣的塊都帶有一個(gè)ID結(jié)構(gòu),其中包含塊的唯一名稱,并在某些情況下,包含一個(gè)指明該塊來自何處的庫。ID結(jié)構(gòu)允許Blender的數(shù)據(jù)被一個(gè)統(tǒng)一的方式操縱,而不需要了解實(shí)際的數(shù)據(jù)類型。

             

            這些ID也讓Blender來內(nèi)部組織文件作為一個(gè)文件結(jié)構(gòu),仿佛它是一個(gè)包含文件的目錄的集合。

             

            這樣的組織方式對(duì)當(dāng)需要組合blender文件或?qū)⑺麄冏鳛橐粋€(gè)庫使用的情形也很重要。

              

                     Data tree as in memory and file                       Scene graph

            Blender
            中所有的數(shù)據(jù)都存儲(chǔ)在一個(gè)主樹上,這實(shí)際上只是一個(gè)塊的列表。這里的數(shù)據(jù)始終駐留,獨(dú)立于無論用戶如何將他們連接在一起。在圖片上面你可以看到一個(gè)'場景圖'是如何從主樹中可用的數(shù)據(jù)來構(gòu)造出來的。

             

            真實(shí)的數(shù)據(jù)仍然在主樹上,這是在場景塊(Scene block)中的進(jìn)一步可視化。它內(nèi)部有一個(gè)基本結(jié)構(gòu)的清單,允許一個(gè)場景去連接許多對(duì)象而不從主結(jié)構(gòu)中刪除他們。

             

            (一個(gè)基礎(chǔ)還允許一些本地屬性,例如層和選擇集(selection),使一個(gè)對(duì)象可以被多個(gè)場景使用而且附帶這些不同的屬性。)

             

            當(dāng)使用BlenderLibrary blocks通常不解放自己(not freed themselves),而只是沒有被連接。他們留在主塊列表中。只有當(dāng)用戶計(jì)數(shù)是零的時(shí)候,這樣的塊才不寫入文件中。

             

            注意上圖中黃色處,這里有兩個(gè)主要的全局變量:當(dāng)前屏幕(也表示活動(dòng)場景)和活動(dòng)對(duì)象。

             

            數(shù)據(jù)塊類型(Data block types)

            所有存儲(chǔ)在主樹中的塊都被稱為Library blocks(有時(shí)也稱為Libdata)。Library blocks啟始的ID結(jié)構(gòu):

             

             1 <ccode>
             2 
             3 typedef struct ID {
             4 
             5 void *next, *prev; /* for inserting in lists */
             6 
             7 struct ID *newid; /* temporal data for finding new links when copying */
             8 
             9 struct Library *lib; /* pointer to the optional Library */
            10 
            11 char name[24]; /* unique name, starting with 2 bytes identifier */
            12 
            13 short us; /* amount of users of the block */
            14 
            15 short flag; /* bitwise flags to indicate special types */
            16 
            17 } ID;
            18 
            19 </ccode>
            20 
            21 

             

            讓我們來仔細(xì)看看Library blocks的其中之一,那個(gè)Mesh。當(dāng)然,這樣一個(gè)塊其實(shí)是許多塊的集合,不論是在數(shù)組中還是在列表中。在這里我們存儲(chǔ)頂點(diǎn),面,UV紋理坐標(biāo),等等(藍(lán)色圖片部分)。這些塊被稱為直接數(shù)據(jù)(Direct Data)。這些數(shù)據(jù)意味著是該網(wǎng)格的直接組成部分,并且總是和一個(gè)網(wǎng)格寫在一起或從文件中讀取回來。

             

            除了這些永久數(shù)據(jù),另外還有一些臨時(shí)數(shù)據(jù)可能會(huì)被連接到這個(gè)網(wǎng)格,例如顯示列表,可以鏈接到網(wǎng)格。這些數(shù)據(jù)總是在匆忙中產(chǎn)生,不寫入文件,并且在從文件中讀回的時(shí)候被設(shè)置為清空。由于所有的庫和Direct Data都保留在文件中,所以將他們?cè)O(shè)計(jì)緊湊并將臨時(shí)數(shù)據(jù)分隔開來很重要。

             

            我們現(xiàn)在得到了Blender設(shè)計(jì)的一個(gè)非常重要的規(guī)則:在Blender使用塊的指針的時(shí)候限于指向指向LibraryData的指針的使用。這意味在任何地方都允許使用指向?qū)ο蠡蚓W(wǎng)格的指針(例如在一個(gè)頂點(diǎn)),但是指向特定定點(diǎn)的指針不能隨意存儲(chǔ)。

             

            譯者注:不是很明確這里的“指針”的含義,暫且認(rèn)為是之前ID STRUCT中的C++指針結(jié)構(gòu)相關(guān)的東西。

             

            這個(gè)規(guī)則確保了一個(gè)一致的和可預(yù)見的結(jié)構(gòu)體,它可以被任何部分的Blender代碼(尤其是對(duì)于數(shù)據(jù)庫管理和文件)使用。它還明確了對(duì)一些東西是否應(yīng)該成為Library Data該如何進(jìn)行決定,當(dāng)你想將它在Blender中到處進(jìn)行交叉引用(crosslinked , re-used)時(shí)會(huì)碰到。

             

            當(dāng)文件被保存后,Direct Data總是緊隨Library Data。由于儲(chǔ)存的數(shù)據(jù)可以包含當(dāng)他們需要讀回時(shí)的指針。這里的指針規(guī)則有助于迅速恢復(fù)所有指向Direct Data的指針,因?yàn)檫@些指針只在一個(gè)單一的和相對(duì)較小的情況下存在。只有指向Library Data的指針才會(huì)存儲(chǔ)在一個(gè)全局表中,并且所有恢復(fù)操作都會(huì)在一個(gè)調(diào)用中立即完成(lib_link_***).

             

            (注:當(dāng)給Blender加入游戲邏輯---傳感器,控制器,執(zhí)行器---最初的決策是將它作為Direct Data駐留在對(duì)象的上下文中。后來出現(xiàn)了對(duì)象傳感器需要在其他對(duì)象上觸發(fā)控制器,這個(gè)特性事實(shí)上因該在Library Data中完成,但是沒有這樣做。一個(gè)很丑陋的補(bǔ)丁就在急匆匆的就被添加到了文件讀取的代碼中。直到目前它仍然是一個(gè)有爭議的設(shè)計(jì)問題。潛在的可能是應(yīng)該用消息執(zhí)行器和消息傳感器來代替。)

             

            外部庫數(shù)據(jù)

             

            以前的一個(gè)設(shè)計(jì)要求是能夠從其他文件中導(dǎo)入數(shù)據(jù),或?qū)⒆鳛橐环N動(dòng)態(tài)鏈接的模板。評(píng)估當(dāng)時(shí)其他3D程序(AliasSoftimage公司)時(shí)我注意到他們都使用的真實(shí)的操作系統(tǒng)文件系統(tǒng);創(chuàng)建一個(gè)項(xiàng)目目錄包含一個(gè)目錄樹并在每一個(gè)目錄中包含一個(gè)數(shù)據(jù)塊對(duì)應(yīng)的文件。除了它非常笨拙和復(fù)雜難于維護(hù),我懷疑這種方式相當(dāng)慢.:)

             

            無論如何,Blender應(yīng)該至少有這種做的好處。這些名為Blender數(shù)據(jù)的使用方式非常類似于文件系統(tǒng)的使用方式,Blender文件是一個(gè)包含所有單個(gè)文件的目錄組合。

             

            當(dāng)使用其他文件(動(dòng)態(tài)鏈接的)中的數(shù)據(jù),很明顯,只有LibraryData中的塊可以被鏈接到。Blender然后自動(dòng)讀取其相關(guān)聯(lián)的Direct Data。不過,為了使從外部文件讀更有用,還需要展開其所有被連接的樹。例如,一個(gè)被鏈接的對(duì)象也將調(diào)用附加的讀取網(wǎng)格、材質(zhì)和紋理。這種展開的數(shù)據(jù)被稱為“間接”。在接口處可以識(shí)別到一個(gè)紅色的庫圖標(biāo)。當(dāng)保存到一個(gè)文件,這些擴(kuò)展的(間接)數(shù)據(jù)根本不會(huì)被寫入。這使得外部文件編輯器可以改變對(duì)象的鏈接,如添加一IPO或添加其他材質(zhì)。

             

            這個(gè)特性的一個(gè)典型的用法是從其他文件動(dòng)態(tài)鏈接一個(gè)場景。無論如何這個(gè)場景永遠(yuǎn)會(huì)被讀取。

             

            當(dāng)保存被連接的Library Data,僅僅它的ID組成部分被寫入文件。然后這個(gè)ID包含一個(gè)指向被使用的“庫”的指針,并且那些真正的IDs有一個(gè)統(tǒng)一的名字用于保證那些鏈接總是被正確的保存。

             

            文件保存和載入

            文件保存大概是通過整個(gè)主樹進(jìn)行,并將所有用戶塊保存為原始二進(jìn)制數(shù)據(jù)轉(zhuǎn)儲(chǔ)到磁盤上。每個(gè)保存的塊有一個(gè)頭(struct BHead)用于存儲(chǔ)附加信息,如在內(nèi)存中這個(gè)塊的原始地址。

             

            讀文件時(shí)先讀整個(gè)文件到內(nèi)存中。 Blender的讀文件代碼接著遍歷所有BHeads,處理Library DataIndirect Data,創(chuàng)建完整的副本。因此,在最后最初讀入的整個(gè)文件可以從內(nèi)存中被釋放。(注:讀和寫大量的數(shù)據(jù)塊是為了防止磁盤和網(wǎng)絡(luò)開銷)。

             

            寫入被動(dòng)態(tài)鏈接的Library Data(Writing dynamic linked library data)

             

            由于Blender的主樹僅僅是另外一個(gè)可以列表化的結(jié)構(gòu),它使用多個(gè)Main以能夠高效的保存和寫入被動(dòng)態(tài)鏈接的數(shù)據(jù)。這是由函數(shù)split_main()完成的,它使用所有的數(shù)據(jù)創(chuàng)建主樹。

             

            為了節(jié)省,當(dāng)前的主樹可以正常處理。至于其他主樹則只保存所有IDs(例如類型ID_ID),以分隔來表示它源自哪個(gè)文件(通過保存結(jié)構(gòu)庫來完成)。

             

            然后,它調(diào)用join_main()來再一次合并所有到一個(gè)單一的主樹。

             

            讀取被動(dòng)態(tài)鏈接的庫數(shù)據(jù)(Reading dynamic linked library data)

             

            這又有點(diǎn)復(fù)雜,也允許遞歸;

             

            1.當(dāng)從文件中讀取數(shù)據(jù),Blender遇到庫結(jié)構(gòu),它創(chuàng)建一個(gè)新的主結(jié)構(gòu)并記得儲(chǔ)存的所有后續(xù)ID_IDs到那里。這些ID得到標(biāo)記LIB_READ

            2.它接著遍歷所有主樹(Main trees),檢查LIB_READ塊標(biāo)記

            3.如果一個(gè)LIB_READ塊發(fā)現(xiàn):

            3.1它檢查包含該數(shù)據(jù)的文件是否已經(jīng)被讀取,如果沒有則加載這整個(gè)文件到內(nèi)存中和并保存到Main

            3.2然后使用正常的讀取規(guī)則讀取塊,連接所有Direct Data到它上面。新的塊被鏈接到當(dāng)前的Main tree,老的塊被清除。

            3.3根據(jù)快的類型不同,它調(diào)用expand_doit()函數(shù),它的像步驟3.2一樣讀取更多的塊,或者檢測這個(gè)塊數(shù)據(jù)是否已經(jīng)被正確讀取。注:當(dāng)這樣的擴(kuò)展的數(shù)據(jù)再一次從另一個(gè)文件出現(xiàn),它只是讀取ID部分,將它鏈接到正確的Main并且標(biāo)記為LIB_READ

            4.只要LIB_READ標(biāo)記的塊被發(fā)現(xiàn),則返回到步驟2

            5.只有在最后,它才加入到Main,并恢復(fù)所有正確的Library Data的指針。

             

            你可以想像得到,這個(gè)系統(tǒng)需要相當(dāng)多的指針技巧,其中指針必須映射到新的指針,然后再一次映射到新的指針,只有用正確的結(jié)束方式將真實(shí)的數(shù)據(jù)分配完成才算數(shù)。

             

            Struct-DNA (SDNA結(jié)構(gòu))

            隨著選擇了將文件保存為二進(jìn)制格式,并了解到Blender的結(jié)構(gòu)總是在變化和擴(kuò)展,我當(dāng)初想設(shè)計(jì)一個(gè)系統(tǒng),可以兼顧到所有的低版本變更。這就是Blender DNA在圖片得到的。

             

            簡單來說,SDNA是一打包并用二進(jìn)制預(yù)處理過的Blender包含文件的一個(gè)版本,其中包含可以保存到文件的數(shù)據(jù)。De SDNA系統(tǒng)然后可以得到結(jié)構(gòu)的內(nèi)容本身,包括它的大小,元素類型和名稱。

             

            每個(gè)編譯的Blender都有類似的SDNA被編譯在其中,并在每個(gè)保存的.blennd文件中這個(gè)SDNA塊都被加進(jìn)來。另外,對(duì)于每一個(gè)文件的BHead它保存了一個(gè)索引數(shù)字表示了結(jié)構(gòu)類型。

             

            當(dāng)檢測和解析到變化時(shí)所有這一切都被允許。例如像一個(gè)shortint的轉(zhuǎn)換,一個(gè)charfloat的轉(zhuǎn)換,或一個(gè)數(shù)組的元素變得越來越少或越來越多。新的變量總是很好的被清零,并且被刪除的變量只是簡單的被跳過。在移植到little endian系統(tǒng)(Blender誕生的時(shí)候使用big endian)的時(shí)候可以很好的進(jìn)行自動(dòng)轉(zhuǎn)換。即使移植到到64位系統(tǒng)(DEC Alpha)也成功的使用SDNA完成了。

             

            此外,它允許向后和向上兼容性。從Blender 1997任何可以很好的讀取2004版的文件,反之亦然。

             

            主要的限制是碰到要求對(duì)一個(gè)真實(shí)的版本進(jìn)行改動(dòng)。例如添加一個(gè)新的變量,它需要初始化一個(gè)特定的指。或者更糟的是,當(dāng)一些變量的意義發(fā)生了變化(例如像物理屬性)。

             

            源代碼的布局(Source code layout

            當(dāng)前源代碼的布局仍然是一個(gè)正在進(jìn)行的工作的一瞥。一些依賴庫已經(jīng)明確的定了下來,其他仍然只是簡短的決定。

            在下圖中你會(huì)發(fā)現(xiàn)文檔中提及的目錄

             

             

            Blender UI framework

            source/blender/src/”目錄中你可以找到所Blender中所有用戶界面和工具相關(guān)的代碼,這個(gè)結(jié)構(gòu)非常清晰,也可以反映到一個(gè)更好的目錄結(jié)構(gòu)上。

             

            posted on 2011-03-16 20:31 的筆記 閱讀(10172) 評(píng)論(1)  編輯 收藏 引用

            評(píng)論

            # re: BLENDER架構(gòu) 2011-07-15 21:50 作者

            歡迎指出錯(cuò)誤。首先本文是原創(chuàng),其次在第一行就聲明了不是嚴(yán)格翻譯。歡迎指出錯(cuò)誤,不歡迎無關(guān)話題的評(píng)論。  回復(fù)  更多評(píng)論   


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久电影网一区| 亚洲成色WWW久久网站| 青青青伊人色综合久久| 久久青青草原精品影院| 青青草原综合久久大伊人导航| 色婷婷久久综合中文久久一本| 久久妇女高潮几次MBA| 久久精品视频网| 色偷偷88欧美精品久久久| 久久精品蜜芽亚洲国产AV| 久久人人爽人人精品视频| 香蕉久久夜色精品升级完成| 中文字幕无码av激情不卡久久| 精品国产乱码久久久久久郑州公司 | 精品国产乱码久久久久久郑州公司| 欧美伊香蕉久久综合类网站| 久久亚洲AV成人无码| 欧美伊香蕉久久综合类网站| 亚洲AV无码久久精品蜜桃| 久久99精品久久久久久野外| 久久精品毛片免费观看| 综合久久国产九一剧情麻豆| 久久久久久国产精品无码下载 | 久久亚洲高清综合| 国内精品久久国产大陆| 亚洲精品乱码久久久久久蜜桃图片| 久久91这里精品国产2020| 99久久精品国产麻豆| 久久婷婷五月综合97色一本一本 | 精品久久久无码人妻中文字幕| 狠狠久久综合| 久久国产视频网| 久久亚洲国产中v天仙www| 99久久精品毛片免费播放| 久久99精品久久只有精品| 久久精品中文騷妇女内射| 亚洲精品乱码久久久久久按摩 | 欧美综合天天夜夜久久| 国产精品久久久久久吹潮| av无码久久久久久不卡网站| 999久久久无码国产精品|