青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

  C++博客 :: 首頁(yè) :: 聯(lián)系 ::  :: 管理
  163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

常用鏈接

留言簿(48)

我參與的團(tuán)隊(duì)

搜索

  •  

積分與排名

  • 積分 - 402521
  • 排名 - 59

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

首先我得說(shuō)我非常喜歡這一章節(jié).Jonathan de Blok使我產(chǎn)生了用OpenGL編寫AVI播放器的想法,可那時(shí),我跟本不知如何打開(kāi)AVI文件,更不必說(shuō)去寫一個(gè)播放器了.于是我瀏覽了搜藏的編程書籍,沒(méi)有一本講到AVI文件的.我又閱讀了MSDN上和AVI文件格式有關(guān)的一切內(nèi)容,上面有很多有用的信息,但我需要更多的.
花了幾小時(shí)在網(wǎng)上搜到AVI范例,只找到兩個(gè)網(wǎng)站.我的搜索技巧不能說(shuō)很棒吧,但99.9%的情況,我能找到我要尋找的東西.了解到AVI范例竟如此之少時(shí),我完全震驚了.大多數(shù)范例并不能編譯通過(guò)...有一些則用了太復(fù)雜的的方法(至少對(duì)我如此),剩下的不錯(cuò),可是用VB,Delphi等寫的(不是用vc++).

找到的第一個(gè)網(wǎng)頁(yè)是Jonathan Nix寫的題為"AVI 文件"的文章.網(wǎng)址是http://www.gamedev.net/reference/programming/features/avifile.感謝Jonathan寫了這片關(guān)于AVI格式的好文章.雖然我用不同的做法,但他的代碼片斷和清晰的注解讓人學(xué)得很輕松!第二個(gè)網(wǎng)站標(biāo)題為"AVI 總體觀"(John F. McGowan, Ph.D寫的)..我可以大肆贊美John的網(wǎng)葉有多么驚奇,但你最好自己去看看.他的網(wǎng)址是http://www.jmcgowan.com/avi.html.這個(gè)網(wǎng)站講到了和AVI格式有關(guān)的幾乎所有內(nèi)容.感謝John做了一個(gè)這么有用的網(wǎng)站.

最后要提到是我沒(méi)有借鑒任何代碼,沒(méi)有抄襲任何代碼.我的代碼是花了三天時(shí)間了解到上述網(wǎng)站和文章的信息后才寫成的.我是想說(shuō)我的代碼也許不是播放AVI文件的最好代碼,他也許不是放AVI文件的正確代碼,但他管用而且使用方便.如果你不喜歡這些代碼和我的編程風(fēng)格,或者覺(jué)得我的言論傷害到整個(gè)編程界,你有以下選擇:1)在網(wǎng)上找到替換的資源2)寫自己的AVI播放器3)寫一篇更好的文章.任何訪問(wèn)本網(wǎng)站的人現(xiàn)在應(yīng)該知道我只是一名中級(jí)程序員(這一點(diǎn)我在網(wǎng)站里很多文章的開(kāi)頭都提到過(guò))!我編寫代碼自樂(lè)而已.本網(wǎng)站的目的在于讓非精英程序員更輕松的開(kāi)始OpenGl編程.這些文章只是關(guān)于我實(shí)現(xiàn)的幾個(gè)特殊的效果...沒(méi)有其他的.

開(kāi)始講代碼首先你要注意的是我們要包括和連接到視頻頭文件和庫(kù)文件.非常感謝微軟(窩不敢相信我說(shuō)了什么).庫(kù)文件使打開(kāi),播放AVI文件都很簡(jiǎn)便.現(xiàn)在你要知道的是必須包括頭文件vfw.h而且要連接到vfw32.lib庫(kù)文件如果想編譯你的代碼的話:)

 
  

#include <vfw.h>                            // Video For Windows頭文件
#include "NeHeGL.h"                        // NeHeGL頭文件

#pragma comment( lib, "opengl32.lib" )               
#pragma comment( lib, "glu32.lib" )               
#pragma comment( lib, "vfw32.lib" )                    // 鏈接到VFW32.lib


GL_Window*    g_window;
Keys*        g_keys;

  
 現(xiàn)在定義變量.angle是用來(lái)根據(jù)時(shí)間來(lái)旋轉(zhuǎn)物體的.為簡(jiǎn)單起見(jiàn)我們用angle來(lái)控制所有的旋轉(zhuǎn).
接下來(lái)是一個(gè)整型變量是用來(lái)計(jì)算經(jīng)過(guò)的時(shí)間(以毫秒計(jì)).它使幀速保持一個(gè)速度.
后面細(xì)講!
frame是動(dòng)畫要顯示的當(dāng)前幀,初始值為0(第一幀).我想如果成功打開(kāi)AVI,他至少有一幀吧,這樣假定比較安全:)
effect是當(dāng)前屏幕上的效果(有:立方體,球體,圓柱體).env是布爾值.若它為true則環(huán)境映射啟動(dòng),若為假,則物體沒(méi)有環(huán)境映射.若bg為true,你會(huì)看到物體后有全屏的動(dòng)畫;若為假,你只會(huì)看到物體(沒(méi)有背景).
sp,ep和bp用來(lái)確定使用者沒(méi)有按著鍵不放. 
  

float        angle;                            // 旋轉(zhuǎn)用
int        next;                            // 動(dòng)畫用
int        frame=0;                            // 幀計(jì)數(shù)器
int        effect;                            // 當(dāng)前效果
bool        sp;                            // 空格鍵按下?
bool        env=TRUE;                            // 環(huán)境映射(默認(rèn)開(kāi))
bool        ep;                            //’E’ 按下?
bool        bg=TRUE;                            // 背景(默認(rèn)開(kāi))
bool        bp;                            // ’B’ 按下?

  
 psi結(jié)構(gòu)體包含AVI文件信息.pavi緩沖的指針,緩沖用來(lái)接受AVI文件打開(kāi)時(shí)的流句柄.pgf是指向GetFrame對(duì)象的指針.bmih在后面的代碼中將被用來(lái)把動(dòng)畫的每一幀轉(zhuǎn)換為我們需要的格式(保存位圖的頭信息).lastframe保存AVI動(dòng)畫最后一幀的序號(hào).width和height保存AVI流的維信息,最后...pdata是圖象數(shù)據(jù)的指針(每次在從AVI中獲得一幀后返回).mpf用來(lái)計(jì)算每幀需要多少毫秒.后面細(xì)談這個(gè)變量. 
  

AVISTREAMINFO        psi;                        // 包含流信息的結(jié)構(gòu)體的指針
PAVISTREAM        pavi;                        // 流句柄
PGETFRAME        pgf;                            // GetFrame對(duì)象的指針
BITMAPINFOHEADER    bmih;                            // 頭信息 For DrawDibDraw
long            lastframe;                    // 流中最后一幀
int            width;                        // 視頻寬
int            height;                        // 視頻高
char            *pdata;                        // 紋理數(shù)據(jù)指針
int            mpf;                        // 控制每幀顯示時(shí)間

  
 在本章中我們用GLU庫(kù)創(chuàng)建兩個(gè)二次曲面(球體和圓柱體).quadratic是曲面對(duì)象的指針.
hdd是DrawDib設(shè)備上下文的句柄.hdc是設(shè)備上下文的句柄.
hBitmap是設(shè)備無(wú)關(guān)位圖的句柄(在后面位圖轉(zhuǎn)換時(shí)用到).
data是最后指向轉(zhuǎn)換后位圖的圖象數(shù)據(jù)的指針,在后面的代碼中會(huì)有意義,往下讀:) 
  

GLUquadricObj *quadratic;                        // 存儲(chǔ)二次曲面對(duì)象

HDRAWDIB hdd;                            // Dib句柄
HBITMAP hBitmap;                            // 設(shè)備無(wú)關(guān)位圖的句柄
HDC hdc = CreateCompatibleDC(0);                    // 創(chuàng)建一個(gè)兼容的設(shè)備上下文
unsigned char* data = 0;                        // 調(diào)整后的圖象數(shù)據(jù)指針

  
 下面使用到匯編語(yǔ)言.那些從來(lái)沒(méi)有用過(guò)匯編的不要被嚇倒了.他看起來(lái)神秘,實(shí)際上非常簡(jiǎn)單!
在寫本章是我發(fā)現(xiàn)了十分奇怪的事.第一次做出來(lái)的可以播放,但色彩混亂了.本來(lái)是紅色的變成藍(lán)色的了,本來(lái)是藍(lán)色的變成紅色的了.我簡(jiǎn)直要發(fā)狂了!我相信我的代碼某處有問(wèn)題.看了一邊代碼還是找不到bug于是又讀了MSDN.為什么紅色與藍(lán)色互換了!?!MSDN明明說(shuō)24比特位圖是RGB啊!又讀了一些東西,我找到了答案.在WINDOWS圖形系統(tǒng)中,RGB數(shù)據(jù)是倒著存儲(chǔ)的(BGR).而在OpenGL中,要用的RGB數(shù)據(jù)就是RGB的順序!

在抱怨了微軟之后:)我決定加一條注解!我不因?yàn)镽GB數(shù)據(jù)倒過(guò)來(lái)存放而打算罵微軟.只是覺(jué)得很奇怪--他叫做RGB實(shí)際上在文件中是按BGR存的!

另:這一點(diǎn)和"little endian"和"big endian"有關(guān).Intel以及Intel兼容產(chǎn)品用little endian--LSB(數(shù)據(jù)最低位)首先存.OpenGL是產(chǎn)生于Silicon Graphics的機(jī)器的,用的是big endian,所以標(biāo)準(zhǔn)的OpenGL要位圖格式是big endian格式.這是我的理解.

棒極了!所以說(shuō)這第一個(gè)播放器就是一個(gè)垃圾!我的解決方法是用一個(gè)循環(huán)把數(shù)據(jù)交換過(guò)來(lái).這能行,但太慢.我又在紋理生成代碼中用GL_BGR_EXT代替了GL_RGB,速度暴升,色彩顯示也對(duì)了!問(wèn)題解決了...原來(lái)我是這樣想!后來(lái)發(fā)現(xiàn)一些OpenGL驅(qū)動(dòng)不支持GL_BGR... :(

與好友Maxwell Sayles討論后,他推薦我用匯編代碼來(lái)交換數(shù)據(jù).一分鐘后,他用icq發(fā)來(lái)下面的代碼!也許不是最優(yōu)化的,但他很快也很有效!

動(dòng)畫的每一幀存在一個(gè)緩沖里.圖象256像素寬,256像素高,每個(gè)色彩一字節(jié)(一像素3字節(jié)).下面的代碼會(huì)掃描整個(gè)緩沖并交換紅與藍(lán)的字節(jié).紅存在ebx+0,藍(lán)存在ebx+2.我們一次向前走3字節(jié)(因?yàn)橐粋€(gè)像素3字節(jié)).不斷掃描直到所有數(shù)據(jù)交換過(guò)來(lái).

你們有些人不喜歡用匯編代碼,所以我想有必要在本章里解釋一下.本來(lái)計(jì)劃用GL_BGR_EXT,他管用,但不是所有的顯卡都支持!我又用異或交換法,這在所有機(jī)器上都是有效的,但不十分快.用了匯編后速度相當(dāng)快.考慮到我們?cè)谔幚韺?shí)時(shí)視頻,你需要最快的交換方法.權(quán)衡了以上選擇,匯編是最好的!如果你有更好的辦法,就用你自己的吧!我并不是告訴你必須如何去做,只是告訴你我的做法.我也會(huì)細(xì)致的解釋代碼.如果你要用更好的代碼來(lái)作替換,你要清楚這些代碼是來(lái)干什么的,自己寫代碼時(shí),要為日后的優(yōu)化提供方便.

 
  

void flipIt(void* buffer)                        // 交換紅藍(lán)數(shù)據(jù)(256x256)
{
    void* b = buffer;                        // 緩沖指針
    __asm                            // 匯編代碼
    {
        mov ecx, 256*256                    // 設(shè)置計(jì)數(shù)器
        mov ebx, b                    // ebx存數(shù)據(jù)指針
        label:                        // 循環(huán)標(biāo)記
            mov al,[ebx+0]                // 把ebx位置的值賦予al
            mov ah,[ebx+2]                // 把ebx+2位置的值賦予ah
            mov [ebx+2],al                // 把a(bǔ)l的值存到ebx+2的位置
            mov [ebx+0],ah                // 把a(bǔ)h的值存到ebx+0的位置

            add ebx,3                    // 向前走3個(gè)字節(jié)
            dec ecx                    // 循環(huán)計(jì)數(shù)器減1
            jnz label                    // ecx非0則跳至label
    }
}

  
 下面的代碼以只讀方式打開(kāi)AVI文件.szFile是打開(kāi)文件的名字.title[100]用來(lái)修改window標(biāo)題(顯示AVI文件信息).
首先調(diào)用AVIFileInit().他初始化AVI文件庫(kù)(使東西能用?鵠?).

打開(kāi)AVI文件有很多方法.我采用AVIStreamOpenFromFile(...).他能打開(kāi)AVI文件中單獨(dú)一個(gè)流(AVI文件可以包含多個(gè)流).它的參數(shù)如下:pavi是接收流句柄的緩沖的指針,szFile是打開(kāi)文件的名字(包括路徑).第三參數(shù)是打開(kāi)的流的類型.在這個(gè)工程里,我們只對(duì)視頻流感興趣(streamtypeVIDEO).第四參數(shù)是0,這表示我們需要第一次讀到的視頻流(一個(gè)AVI文件里會(huì)有多個(gè)視頻流,我們要第一個(gè)).OF_READ表示以只讀方式打開(kāi)文件.最后一個(gè)參數(shù)是一個(gè)類標(biāo)識(shí)句柄的指針.說(shuō)實(shí)話,我也不清楚他是干嗎的.我讓windows自己設(shè)定,于是把NULL傳過(guò)去.

 
  

void OpenAVI(LPCSTR szFile)                        // 打開(kāi)AVI文件szFile
{
    TCHAR    title[100];                    // 包含修改了的window標(biāo)題

    AVIFileInit();                        // 打開(kāi)AVI文件庫(kù)

    // 打開(kāi)AVI流
    if (AVIStreamOpenFromFile(&pavi, szFile, streamtypeVIDEO, 0, OF_READ, NULL) !=0)
    {
        // 打開(kāi)流時(shí)的出錯(cuò)處理
        MessageBox (HWND_DESKTOP, "打開(kāi)AVI流失敗", "錯(cuò)誤", MB_OK | MB_ICONEXCLAMATION);
    }

  
 到目前為止,我們假定文件被正確打開(kāi),流被正確定位!然后用AVIStreamInfo(...)從AVI文件里抓取一些信息.
先前我們創(chuàng)建了叫psi的結(jié)構(gòu)體來(lái)保存AVI流的信息.下面第一行,我們把AVI信息填入該結(jié)構(gòu)體.從流的寬度(以像素計(jì))到動(dòng)畫的幀速等所有的信息都會(huì)存到psi中.那些想要精確控制播放速度的要記住我剛才說(shuō)的.更多的信息參閱MSDN.

我們通過(guò)右邊位置減左邊位置算出幀寬.這個(gè)結(jié)果是以像素記的精確的幀寬.至于高度,可以用底邊位置減頂邊位置得到.這樣得到高度的像素值.

然后用AVIStreamLength(...)得到AVI文件最后一幀的序號(hào).AVIStreamLength(...)返回動(dòng)畫最后一幀的序號(hào).結(jié)果存在lastframe里.

計(jì)算幀速很簡(jiǎn)單.每秒幀速(fps)= psi.dwRate/psi,dwScale.返回的值應(yīng)該匹配顯示幀的速度(你在AVI動(dòng)畫中右擊鼠標(biāo)可以看到).你會(huì)問(wèn)那么這和mpf有什么關(guān)系呢?第一次寫這個(gè)代碼時(shí),我試著用fps來(lái)選擇動(dòng)畫了正確的幀面.我遇到一個(gè)問(wèn)題...視頻放的太快!于是我看了一下視頻屬性.face2.avi文件有3.36秒長(zhǎng).幀速是29.974fps.視頻動(dòng)畫共有91幀.而3.36*29.974 = 100.71.非常奇怪!!

所以我采用一些不同的方法.不是計(jì)算幀速,我計(jì)算每一幀播放所需時(shí)間.AVIStreamSampleToTime()把在動(dòng)畫中的位置轉(zhuǎn)換位你到達(dá)該位置所需的時(shí)間(毫秒計(jì)).所以通過(guò)計(jì)算到達(dá)最后一幀的時(shí)間就得到整個(gè)動(dòng)畫的播放時(shí)間.再拿這個(gè)結(jié)果除以動(dòng)畫總幀數(shù)(lastframe).這樣就給出了每幀的顯示時(shí)間(毫秒計(jì)).結(jié)果存在mpf(milliseconds per frame)里.你也能通過(guò)獲取動(dòng)畫中一幀的時(shí)間來(lái)算每幀的毫秒數(shù),代碼為:AVIStreamSampleToTime(pavi,1).兩種方法都不錯(cuò)!非常感謝Albert Chaulk提供思路!

我說(shuō)每幀的毫秒數(shù)不精確是因?yàn)閙pf是一個(gè)整型值,所以所有的浮點(diǎn)數(shù)都會(huì)被取整.

 
  

    AVIStreamInfo(pavi, &psi, sizeof(psi));            // 把流信息讀進(jìn)psi
    width=psi.rcFrame.right-psi.rcFrame.left;            // 寬度為右邊減左邊
    height=psi.rcFrame.bottom-psi.rcFrame.top;            // 高為底邊減頂邊

    lastframe=AVIStreamLength(pavi);                // 最后一幀的序號(hào)

    mpf=AVIStreamSampleToTime(pavi,lastframe)/lastframe;        // mpf的不精確值

  
 因?yàn)镺penGL需要紋理數(shù)據(jù)是2的冪,而大多視頻是160*120,320*240等等,所以需要一種把視頻格式重調(diào)整為能用作紋理的格式.我們可利用Windows Dib函數(shù)去做.
首先要做的是描述我們想要的圖像的類型.于是我們要以所需參數(shù)填好bmih這個(gè)BitmapInfoHeader結(jié)構(gòu).
首先設(shè)定該結(jié)構(gòu)體的大小.再把位平面數(shù)設(shè)為1.3字節(jié)的數(shù)據(jù)有24比特(RGB).要使圖像位256像素寬,256像素高,最后要讓數(shù)據(jù)返回為UNCOMPRESSED(非壓縮)的RGB數(shù)據(jù)(BI_RGB).

CreateDIBSection創(chuàng)建一個(gè)可直接寫的設(shè)備無(wú)關(guān)位圖(dib).如果一切順利,hBitmap會(huì)指向該dib的比特值.hdc是設(shè)備上下文(DC)的句柄第二參數(shù)是BitmapInfo結(jié)構(gòu)體的指針.該結(jié)構(gòu)體包含了上述dib文件的信息.第三參數(shù)(DIB_RGB_COLORS)設(shè)定數(shù)據(jù)是RGB值.data是指向DIB比特值位置的指針的指針(嗚,真繞口).第五參數(shù)設(shè)為NULL,我們的DIB已被分配好內(nèi)存.末了,最后一個(gè)參數(shù)可忽略(設(shè)為NULL).

引自MSDN:SelecObject函數(shù)選一個(gè)對(duì)象進(jìn)入設(shè)備上下文(DC).

現(xiàn)在我們建好一個(gè)能直接寫的DIB,yeah:)

 
  

    bmih.biSize        = sizeof (BITMAPINFOHEADER);        // BitmapInfoHeader的大小
    bmih.biPlanes        = 1;                    // 位平面
    bmih.biBitCount        = 24;                    //比特格式(24 Bit, 3 Bytes)
    bmih.biWidth        = 256;                    // 寬度(256 Pixels)
    bmih.biHeight        = 256;                    // 高度 (256 Pixels)
    bmih.biCompression    = BI_RGB;                        // 申請(qǐng)的模式 = RGB

    hBitmap = CreateDIBSection (hdc, (BITMAPINFO*)(&bmih), DIB_RGB_COLORS, (void**)(&data), NULL, NULL);
    SelectObject (hdc, hBitmap);                    // 選hBitmap進(jìn)入設(shè)備上下文(hdc)

  
 在從AVI中讀取幀面前還有幾件事要做.接下來(lái)使程序做好從AVI文件中解出幀面的準(zhǔn)備.用AVIStreamGetFrameOpen(...)函數(shù)做這一點(diǎn).
你能給這個(gè)函數(shù)傳一個(gè)結(jié)構(gòu)體作為第二參數(shù)(它會(huì)返回一個(gè)特定的視頻格式).糟糕的是,你能改變的唯一數(shù)據(jù)是返回的圖像的寬度和高度.MSDN也提到能傳AVIGETFRAMEF_BESTDISPLAYFMT為參數(shù)來(lái)選擇一個(gè)最佳顯示格式.奇怪的是,我的編譯器沒(méi)有定義這玩藝兒.

如果一切順利,一個(gè)GETFRAME對(duì)象被返回(用來(lái)讀幀數(shù)據(jù)).有問(wèn)題的話,提示框會(huì)出現(xiàn)在屏幕上告訴你有錯(cuò)誤!

 
  

    pgf=AVIStreamGetFrameOpen(pavi, NULL);                // 用要求的模式建PGETFRAME
    if (pgf==NULL)
    {
        // 解幀出錯(cuò)
        MessageBox (HWND_DESKTOP, "不能打開(kāi)AVI幀", "錯(cuò)誤", MB_OK | MB_ICONEXCLAMATION);
    }

  
 下面的代碼把視頻寬,高和幀數(shù)傳給window標(biāo)題.用函數(shù)SetWindowText(...)在window頂部顯示標(biāo)題.以窗口模式運(yùn)行程序看看以下代碼的作用. 
  

    // bt標(biāo)題欄信息(寬 / 高/ 幀數(shù))
    wsprintf (title, "NeHe's AVI Player: Width: %d, Height: %d, Frames: %d", width, height, lastframe);
    SetWindowText(g_window->hWnd, title);                // 修改標(biāo)題欄
}

  
 下面是有趣的東西...從AVI中抓取一幀,把它轉(zhuǎn)為大小和色深可用的圖象.lpbi包含一幀的BitmapInfoHeader信息.我們?cè)谙旅娴诙型瓿闪藥准?先是抓了動(dòng)畫的一幀...我們需要的幀面由這些幀確定.這會(huì)讓動(dòng)畫走掉這一幀,lpbi會(huì)指向這一幀的頭信息.
下面是有趣的東西...我們要指向圖像數(shù)據(jù)了.要跳過(guò)頭信息(lpbi->biSize).一件事直到寫本文時(shí)我才意識(shí)到:也要跳過(guò)任何的色彩信息.所以要跳過(guò)biClrUsed*sizeof(RGBQUAD)(譯者:我想他是說(shuō)要跳過(guò)調(diào)色板信息).做完這一切,我們就得到圖像數(shù)據(jù)的指針了(pdata).

也要把動(dòng)畫的每一幀的大小轉(zhuǎn)為紋理能用的大小,還要把數(shù)據(jù)轉(zhuǎn)為RGB數(shù)據(jù).這用到DrawDibDraw(...).

一個(gè)大概的解釋.我們能直接寫設(shè)定的DIB圖像.那就是DrawDibDraw(...)所做的.第一參數(shù)是DrawDib DC的句柄.第二參數(shù)是DC的句柄.接下來(lái)用左上角(0,0)和右下角(256,256)構(gòu)成目標(biāo)矩形.

lpbi指向剛讀的幀的bitmapinfoheader信息.pdata是剛讀的幀的圖像數(shù)據(jù)指針.

再把源圖象(剛讀的幀)的左上角設(shè)為(0,0),右下角設(shè)為(幀寬,幀高).最后的參數(shù)應(yīng)設(shè)為0.

這個(gè)方法可把任何大小、色深的圖像轉(zhuǎn)為256*256*24bit的圖像.

 
  

void GrabAVIFrame(int frame)                        // 從流中抓取一幀
{
    LPBITMAPINFOHEADER lpbi;                        // 存位圖的頭信息
    lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(pgf, frame);        // 從AVI流中得到數(shù)據(jù)
    pdata=(char *)lpbi+lpbi->biSize+lpbi->biClrUsed * sizeof(RGBQUAD);    // 數(shù)據(jù)指針,由AVIStreamGetFrame返回(跳過(guò)頭
//信息和色彩信息)
// 把數(shù)據(jù)轉(zhuǎn)為所需格式
    DrawDibDraw (hdd, hdc, 0, 0, 256, 256, lpbi, pdata, 0, 0, width, height, 0);

  
 我們得到動(dòng)畫的每幀數(shù)據(jù)(紅藍(lán)數(shù)據(jù)顛倒的).為解決這個(gè)問(wèn)題,我們的高速代碼flipIt(...).記住,data是指向DIB比特值位置的指針的指針變量.這意味著調(diào)用DrawDibDraw后,data指向一個(gè)調(diào)整過(guò)大小(256*256),修改過(guò)色深(24bits)的位圖數(shù)據(jù).
原來(lái)我通過(guò)重建動(dòng)畫的每一幀來(lái)更新紋理.我收到幾封email建議我用glTexSubImage2D().翻閱了OpenGL紅寶書后,我磕磕絆絆的寫出下面注釋:"創(chuàng)建紋理的計(jì)算消耗比修改紋理要大.在OpenGL1.1版本中,有幾條調(diào)用能更新全部或部分紋理圖像信息.這對(duì)某些應(yīng)用程序有用,比如實(shí)時(shí)的抓取視頻圖像作紋理.對(duì)于這些程序,用glTexSubImage2D()根據(jù)新視頻圖像來(lái)創(chuàng)建單個(gè)紋理以代替舊的紋理數(shù)據(jù)是行得通的."

在我個(gè)人并沒(méi)有發(fā)現(xiàn)速度明顯加快,也許在低端顯卡上才會(huì).glTexSubImage2D()的參數(shù)是:目標(biāo)是一個(gè)二維紋理(GL_TEXTURE_2D).細(xì)節(jié)級(jí)別(0),mipmapping用.x(0),y(0)告訴OpenGL開(kāi)始拷貝的位置(0,0是紋理的左下角).然后是圖像的寬度,我們要拷貝的圖像是256像素寬,256像素高.GL_RGB是我們的數(shù)據(jù)格式.我們?cè)诳截悷o(wú)符號(hào)byte.最后...圖像數(shù)據(jù)指針----data.非常簡(jiǎn)單!

Kevin Rogers 另加:我想指出使用glTexSubImage2D()另一個(gè)重要原因.不僅因?yàn)樵谠S多OpenGL實(shí)現(xiàn)中它很快,還因?yàn)槟繕?biāo)區(qū)不必是2的冪.這對(duì)視頻重放很方便,因?yàn)橐粠木S通常不是2的冪(而是像320*200之類的).這樣給了你很大機(jī)動(dòng)性,你可以按視頻流原本的樣子播放,而不是扭曲或剪切每一幀來(lái)適應(yīng)紋理的維.

重要的是你不能更新一個(gè)紋理如果你第一次沒(méi)有創(chuàng)建他!我們?cè)贗nitialize()中創(chuàng)建紋理.

還要提到的是...如果你計(jì)劃在工程里使用多個(gè)紋理,務(wù)必綁住你要更新的紋理.否則,更新出來(lái)的紋理也許不是你想要的!

 
  

    flipIt(data);                            // 交換紅藍(lán)數(shù)據(jù)

    // 更新紋理
    glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 256, 256, GL_RGB, GL_UNSIGNED_BYTE, data);
}

  
 接下來(lái)的部分當(dāng)程序退出時(shí)調(diào)用,我們關(guān)掉DrawDib DC,釋放占用的資源.然后釋放AVI GetFrame資源.最后釋放AVI流和文件. 
  

void CloseAVI(void)                            // 關(guān)掉AVI資源
{
    DeleteObject(hBitmap);                        //釋放設(shè)備無(wú)關(guān)位圖信息
    DrawDibClose(hdd);                            // 關(guān)掉DrawDib DC
    AVIStreamGetFrameClose(pgf);                    // 釋放AVI GetFrame資源
    AVIStreamRelease(pavi);                        // 釋放AVI流
    AVIFileExit();                            // 釋放AVI文件
}

  
 初始化很簡(jiǎn)明.設(shè)初始的angle為0.再打開(kāi)DrawDib庫(kù)(得到一個(gè)DC).一切順利的話,hdd會(huì)是新創(chuàng)建的dc的句柄.
以黑色清屏,開(kāi)啟深度測(cè)試,等等.

然后建一個(gè)新的二次曲面.quadratic是這個(gè)新對(duì)象的指針.設(shè)置光滑的法線,允許紋理坐標(biāo)的生成.

 
  

BOOL Initialize (GL_Window* window, Keys* keys)
{
    g_window    = window;
    g_keys        = keys;

    // 開(kāi)始用戶的初始
    angle = 0.0f;                            // angle為0先
    hdd = DrawDibOpen();                        // 得到Dib的DC
    glClearColor (0.0f, 0.0f, 0.0f, 0.5f);                // 黑色背景
    glClearDepth (1.0f);                        // 深度緩沖初始
    glDepthFunc (GL_LEQUAL);                        // 深度測(cè)試的類型(小于或等于)
    glEnable(GL_DEPTH_TEST);                        // 開(kāi)啟深度測(cè)試
    glShadeModel (GL_SMOOTH);                        // 平滑效果
    glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);            // 透視圖計(jì)算設(shè)為 //最高精度

    quadratic=gluNewQuadric();                        // 建二次曲面的指針
    gluQuadricNormals(quadratic, GLU_SMOOTH);                // 設(shè)置光滑的法線
    gluQuadricTexture(quadratic, GL_TRUE);                // 創(chuàng)建紋理坐標(biāo)

  
 下面的代碼中,我們開(kāi)啟2D紋理映射,紋理濾鏡設(shè)為GLNEAREST(最快,但看起來(lái)很糙),建立球面映射(為了實(shí)現(xiàn)環(huán)境映射效果).試試其它濾鏡,如果你有條件,可以試試GLLINEAR得到一個(gè)平滑的動(dòng)畫效果.
設(shè)完紋理和球面映射,我們打開(kāi).AVI文件.我盡量使事情簡(jiǎn)單化...你能看出來(lái)么:)我們要打開(kāi)的文件叫作facec2.avi

 
  

    glEnable(GL_TEXTURE_2D);                    // 開(kāi)啟2D紋理映射
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);// 設(shè)置紋理濾鏡
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);

    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);        // 設(shè)紋理坐標(biāo)生成模式為s
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);        // 設(shè)紋理坐標(biāo)生成模式為t

    OpenAVI("data/face2.avi");                    // 打開(kāi)AVI文件

    // 創(chuàng)建紋理
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

    return TRUE;                        // 初始化成功返回TRUE
}

  
 關(guān)閉時(shí)調(diào)用CloseAVI().他正確的關(guān)閉AVI文件,并釋放所有占用資源. 
  

void Deinitialize (void)                        // 做所有的釋放工作
{
    CloseAVI();                        // 關(guān)閉AVI文件
}

  
 到了檢查按鍵和更新旋轉(zhuǎn)角度的地方了.我知道再?zèng)]有必要詳細(xì)解釋這些代碼了.我們檢查空格鍵是否按下,若是,則增加effect值.有3種效果(立方,球,圓柱)第四個(gè)效果被選時(shí)(effect = 3)不畫任何對(duì)象...僅顯示背景!如果選了第四效果,空格又按下了,就重設(shè)為第一個(gè)效果(effect = 0).Yeah,我本該叫他對(duì)象:)
然后檢查’b’鍵是否按下,若是,則改變背景(bg從ON到OFF或從OFF到ON).

環(huán)境映射的鍵設(shè)置也一樣.檢查’E’是否按下,若是則改變env從TRUE到FALSE或從FALSE到TRUE.僅僅是關(guān)閉或開(kāi)啟環(huán)境映射!

每次調(diào)用Updata()時(shí)angle都加上一個(gè)小分?jǐn)?shù).我用經(jīng)過(guò)的時(shí)間除以60.0f使速度降一點(diǎn).

 
  

void Update (DWORD milliseconds)                    // 動(dòng)畫更新
{
    if (g_keys->keyDown [VK_ESCAPE] == TRUE)            //ESC按下?
    {
        TerminateApplication (g_window);            // 關(guān)閉程序
    }

    if (g_keys->keyDown [VK_F1] == TRUE)                // F1按下?
    {
        ToggleFullscreen (g_window);            // 改變顯示模式
    }

    if ((g_keys->keyDown [' ']) && !sp)                // 空格按下并已松開(kāi)
    {
        sp=TRUE;                        // 設(shè)sp為True
        effect++;                        // 增加effect
        if (effect>3)                    // 超出界限?
            effect=0;                    // 重設(shè)為0
    }

    if (!g_keys->keyDown[' '])                    // 空格沒(méi)按下?
        sp=FALSE;                        // 設(shè)sp為False

    if ((g_keys->keyDown ['B']) && !bp)                // ’B’按下并已松開(kāi)
    {
        bp=TRUE;                        // 設(shè)bp為True
        bg=!bg;                        // 改變背景 Off/On
    }

    if (!g_keys->keyDown['B'])                    // ’B’沒(méi)按下?
        bp=FALSE;                        // 設(shè)bp為False

    if ((g_keys->keyDown ['E']) && !ep)                //  ’E’按下并已松開(kāi)
    {
        ep=TRUE;                        // 設(shè)ep為True
        env=!env;                        // 改變環(huán)境映射 Off/On
    }

    if (!g_keys->keyDown['E'])                    //’E’沒(méi)按下
        ep=FALSE;                        // 設(shè)ep為False

    angle += (float)(milliseconds) / 60.0f;            // 根據(jù)時(shí)間更新angle

  
 在原來(lái)的文章里,所有的AVI文件都以相同的速度播放.于是,我重寫了本文讓視頻以正常的速度播放.next增加經(jīng)過(guò)的毫秒數(shù).如果你記得文章的前面,我們算出了顯示每幀的毫秒數(shù)(mpf).為了計(jì)算當(dāng)前幀,我們拿經(jīng)過(guò)的時(shí)間除以顯示每幀的毫秒數(shù)(mpf).
還要檢查確定當(dāng)前幀沒(méi)有超過(guò)視頻的最后幀.若超過(guò)了,則將frame設(shè)為0,動(dòng)畫計(jì)時(shí)器設(shè)為0,于是動(dòng)畫從頭開(kāi)始.

下面的代碼會(huì)丟掉一些幀,若果你的計(jì)算機(jī)太慢的話,
或者另一個(gè)程序占用了CPU.如果想顯示每一幀而不管計(jì)算機(jī)有多慢的話,你要檢查next是否比mpf大,若是,你要把next設(shè)為0,frame增1.兩種方法都行,雖然下面的代碼更有利于跑的快的機(jī)器.

如果你有干勁,試著加上循環(huán),快速播放,暫停或倒放等功能.

 
  

    next+= milliseconds;                        // 根據(jù)時(shí)間增加next
    frame=next/mpf;                            // 計(jì)算當(dāng)前幀號(hào)

    if (frame>=lastframe)                        // 超過(guò)最后一幀?
    {
        frame=0;                            // Frame設(shè)為0
        next=0;                            // 重設(shè)動(dòng)畫計(jì)時(shí)器
    }
}

  
 下面是畫屏代碼:)我們清屏和深度緩沖.再抓取動(dòng)畫的一幀.我將使這更簡(jiǎn)單!把你想要的幀數(shù)傳給GrabAVIFrame().非常簡(jiǎn)單!當(dāng)然,如果是多個(gè)AVI,你要傳一個(gè)紋理標(biāo)號(hào).(你要做更多的事) 
  

void Draw (void)                            // 繪制我們的屏幕
{
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        // 清屏和深度緩沖

    GrabAVIFrame(frame);                    // 抓取動(dòng)畫的一幀

  
 下面檢查我們是否想畫一個(gè)背景圖.若bg是TRUE,重設(shè)模型視角矩陣,畫一個(gè)單紋理映射的能蓋住整個(gè)屏幕的矩形(紋理是從AVI從得到的一幀).矩形距離屏面向里20個(gè)單位,這樣它看起來(lái)在對(duì)象之后(距離更遠(yuǎn)). 
  

    if (bg)                            // 背景可見(jiàn)?
    {
        glLoadIdentity();                    // 重設(shè)模型視角矩陣
        glBegin(GL_QUADS);                    // 開(kāi)始畫背景(一個(gè)矩形)
            // 正面
            glTexCoord2f(1.0f, 1.0f); glVertex3f( 11.0f,  8.3f, -20.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex3f(-11.0f,  8.3f, -20.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f(-11.0f, -8.3f, -20.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex3f( 11.0f, -8.3f, -20.0f);
        glEnd();                       
    }

  
 畫完背景(或沒(méi)有),重設(shè)模型視角矩陣(使視角中心回到屏幕中央).視角中心再向屏內(nèi)移進(jìn)10個(gè)單位.然后檢查env是否為TRUE.若是,開(kāi)啟球面映射來(lái)實(shí)現(xiàn)環(huán)境映射效果.
 
  

    glLoadIdentity ();                        // 重設(shè)模型視角矩陣
    glTranslatef (0.0f, 0.0f, -10.0f);                // 視角中心再向屏內(nèi)移進(jìn)10個(gè)單位

    if (env)                            // 環(huán)境映射開(kāi)啟?
    {
        glEnable(GL_TEXTURE_GEN_S);                // 開(kāi)啟紋理坐標(biāo)生成S坐標(biāo)
        glEnable(GL_TEXTURE_GEN_T);                // 開(kāi)啟紋理坐標(biāo)生成T坐標(biāo)
    }

  
 在最后關(guān)頭我加了以下代碼.他繞X軸和Y軸旋轉(zhuǎn)(根據(jù)angle的值)然后在Z軸方向移動(dòng)2單位.這使我們離開(kāi)了屏幕中心.如果刪掉下面三行,對(duì)象會(huì)在屏幕中心打轉(zhuǎn).有了下面三行,對(duì)象旋轉(zhuǎn)時(shí)看起來(lái)離我們遠(yuǎn)一些:)
如果你不懂旋轉(zhuǎn)和平移...你就不該讀這一章:)

 
  

    glRotatef(angle*2.3f,1.0f,0.0f,0.0f);                // 加旋轉(zhuǎn)讓東西動(dòng)起來(lái)
    glRotatef(angle*1.8f,0.0f,1.0f,0.0f);                // 加旋轉(zhuǎn)讓東西動(dòng)起來(lái)
    glTranslatef(0.0f,0.0f,2.0f);                    // 旋轉(zhuǎn)后平移到新位置

  
 下面的代碼檢查我們要畫哪一個(gè)對(duì)象.若effect為0,我們做一些旋轉(zhuǎn)在畫一個(gè)立方體.這個(gè)旋轉(zhuǎn)使立方體繞X,Y,Z軸旋轉(zhuǎn).現(xiàn)在你腦中該烙下建一個(gè)立方體的方法了吧:) 
  

    switch (effect)                            // 哪個(gè)效果?
    {
    case 0:                                // 效果 0 - 立方體
        glRotatef (angle*1.3f, 1.0f, 0.0f, 0.0f);       
        glRotatef (angle*1.1f, 0.0f, 1.0f, 0.0f);       
        glRotatef (angle*1.2f, 0.0f, 0.0f, 1.0f);       
        glBegin(GL_QUADS);               
            glNormal3f( 0.0f, 0.0f, 0.5f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
           
            glNormal3f( 0.0f, 0.0f,-0.5f);
            glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
       
            glNormal3f( 0.0f, 0.5f, 0.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
           
            glNormal3f( 0.0f,-0.5f, 0.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
       
            glNormal3f( 0.5f, 0.0f, 0.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
       
            glNormal3f(-0.5f, 0.0f, 0.0f);
            glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
        glEnd();                       
        break;                       
  
 下面是畫球體的地方.開(kāi)始先繞X,Y,Z軸旋轉(zhuǎn),再畫球體.球體半徑為1.3f,20經(jīng)線,20緯線.我用20是因?yàn)槲覜](méi)打算讓球體非常光滑.少用些經(jīng)緯數(shù),使球看起來(lái)不那么光滑,這樣球轉(zhuǎn)起來(lái)時(shí)就能看到球面映射的效果(當(dāng)然球面映射必須開(kāi)啟).試著嘗試其它值!要知道,使用更多的經(jīng)緯數(shù)需要更強(qiáng)的計(jì)算能力! 
  

    case 1:                                // 效果1,球體
        glRotatef (angle*1.3f, 1.0f, 0.0f, 0.0f);       
        glRotatef (angle*1.1f, 0.0f, 1.0f, 0.0f);       
        glRotatef (angle*1.2f, 0.0f, 0.0f, 1.0f);       
        gluSphere(quadratic,1.3f,20,20);           
        break;                           
  
 下面畫圓柱.開(kāi)始先繞X,Y,Z軸旋轉(zhuǎn),圓柱頂和底的半徑都為1.0f.高3.0f,32經(jīng)線,32緯線.若減少經(jīng)緯數(shù),圓柱的組成多邊形會(huì)減少,他看起來(lái)就沒(méi)那么圓. 
  

    case 2:                                // 效果2,圓柱
        glRotatef (angle*1.3f, 1.0f, 0.0f, 0.0f);       
        glRotatef (angle*1.1f, 0.0f, 1.0f, 0.0f);       
        glRotatef (angle*1.2f, 0.0f, 0.0f, 1.0f);       
        glTranslatef(0.0f,0.0f,-1.5f);               
        gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);       
        break;                           
    }

  
 下面檢查env是否為TRUE,若是,關(guān)閉球面映射.調(diào)用glFlush()清空渲染流水線(使在下一幀開(kāi)始前一切都渲染了). 
  

    if (env)                                // 是否開(kāi)啟了環(huán)境渲染
    {
        glDisable(GL_TEXTURE_GEN_S);                // 關(guān)閉紋理坐標(biāo)S
        glDisable(GL_TEXTURE_GEN_T);                // 關(guān)閉紋理坐標(biāo)T
    }

    glFlush ();                            // 清空渲染流水線
}

  
 希望你們喜歡這一章.現(xiàn)在已經(jīng)凌晨?jī)牲c(diǎn)了(譯者oak:譯到這時(shí)剛好也是2:00am!)...寫這章花了我6小時(shí)了.聽(tīng)起來(lái)不可思議,可要把東西寫通不是件容易的事.本文我讀了三邊,我力圖使文章好懂.不管你信還是不信,對(duì)我最重要的是你們能明白代碼是怎樣運(yùn)作的,它為什么能行.那就是我喋喋不休并且加了過(guò)量注解的原因.
無(wú)論如何,我都想聽(tīng)到本文的反饋.如果你找到文章的錯(cuò)誤,并想幫我做一些改進(jìn),請(qǐng)聯(lián)系我.就像我說(shuō)的那樣,這是我第一次寫和AVI有關(guān)的代碼.通常我不會(huì)寫一個(gè)我才接觸到的主題,但我太興奮了,并且考慮到關(guān)于這方面的文章太少了.我所希望的是,我打開(kāi)了編寫高質(zhì)量AVI demo和代碼的一扇門!也許成功,也許沒(méi)有.不管怎樣,你可以任意處理我的代碼.

非常感謝 Fredster提供face AVI文件.Face是他發(fā)來(lái)的六個(gè)AVI動(dòng)畫中的一個(gè).他沒(méi)提出任何問(wèn)題和條件.他以他的方式幫助了我,謝謝他!

更要感謝Jonathan de Blok,要沒(méi)要她,本文就不會(huì)有.他給我發(fā)來(lái)他的AVI播放器的代碼,這使我對(duì)AVI格式產(chǎn)生了興趣.他也回答了我問(wèn)的關(guān)于他的代碼的問(wèn)題.但重要的是我并沒(méi)有借鑒或抄襲他的代碼,他的代碼只是幫助我理解AVI播放器的運(yùn)行機(jī)制.我的播放器的打開(kāi),解幀和播放AVI文件用的是不同的代碼!

感謝給予幫助的所有人,包括所有參觀者!若沒(méi)有你們,我的網(wǎng)站不值一文!!!

 
 
posted on 2007-12-24 16:18 sdfasdf 閱讀(1566) 評(píng)論(0)  編輯 收藏 引用 所屬分類: OPENGL
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            一本久道久久综合狠狠爱| 欧美一区二区在线免费观看| 一区二区免费看| 韩日成人av| 一区在线影院| 尤物精品国产第一福利三区 | 免费日韩av片| 免费成人毛片| 欧美国产日本韩| 亚洲激情一区二区| 亚洲国产精品尤物yw在线观看| 亚洲国产一成人久久精品| 亚洲电影免费观看高清完整版在线| 亚洲欧洲一区二区三区| 亚洲一区日韩| 狼狼综合久久久久综合网| 欧美日本国产| 国产欧美日韩亚洲| 亚洲欧洲在线播放| 亚洲欧美视频一区二区三区| 久久综合狠狠综合久久综青草| 欧美福利影院| 亚洲一二三区精品| 久久九九有精品国产23| 欧美精品日韩一区| 国产欧美日韩不卡| 亚洲精品久久久久中文字幕欢迎你| 亚洲视频在线视频| 美女黄网久久| 亚洲一区bb| 欧美成人蜜桃| 国产视频综合在线| 一本一本a久久| 老色批av在线精品| 亚洲麻豆视频| 久久综合狠狠综合久久综合88| 欧美性感一类影片在线播放| 悠悠资源网亚洲青| 久久精品二区三区| 亚洲视频在线二区| 欧美va天堂va视频va在线| 国模吧视频一区| 亚洲一区免费在线观看| 亚洲国产精品成人综合色在线婷婷| 亚洲免费在线观看| 欧美日韩在线不卡| 亚洲一区二区不卡免费| 欧美激情无毛| 久久国产加勒比精品无码| 欧美日韩精品在线播放| 亚洲国产成人高清精品| 欧美一区二区视频在线观看| 国产精品99久久久久久久久久久久 | 一区二区三区免费观看| 欧美成人一二三| 在线看无码的免费网站| 久久久久久夜精品精品免费| 亚洲一区国产一区| 国产精品欧美精品| 性欧美激情精品| 亚洲砖区区免费| 国产日产欧美精品| 久久精品在线观看| 久久国产66| 在线免费观看欧美| 欧美成人一区二区三区| 免费短视频成人日韩| 亚洲韩国精品一区| 亚洲欧洲在线一区| 欧美午夜不卡在线观看免费| 亚洲欧美日韩精品久久亚洲区| aaa亚洲精品一二三区| 国产精品福利影院| 久久精品国产久精国产一老狼| 欧美在线1区| 一区二区三区在线看| 欧美国产精品va在线观看| 欧美激情女人20p| 亚洲午夜羞羞片| 午夜精品久久久久久久99黑人| 亚洲欧美一区二区三区久久| 日韩视频在线一区二区| 国产精品福利久久久| 久久久久久久久久看片| 久久激情婷婷| 亚洲精选久久| 亚洲图片欧美午夜| 伊人成人在线视频| 亚洲激情电影中文字幕| 国产精品福利片| 浪潮色综合久久天堂| 欧美精品亚洲| 久久久青草婷婷精品综合日韩| 欧美激情视频在线播放| 欧美在线一区二区三区| 免费观看一区| 欧美一区二粉嫩精品国产一线天| 久久精品免费看| 99国内精品| 久久久久久久一区| 亚洲欧美成人在线| 久久这里有精品15一区二区三区| 亚洲免费在线观看视频| 国产日韩欧美精品一区| 久久久免费精品| 欧美日韩精品免费观看视一区二区 | 中文国产一区| 午夜一区二区三视频在线观看| 樱花yy私人影院亚洲| 中文在线资源观看网站视频免费不卡| 国产亚洲综合精品| 一本色道久久综合狠狠躁的推荐| 精品成人一区二区三区| 亚洲欧美激情一区| 夜夜夜久久久| 麻豆久久久9性大片| 国产精品久久久久aaaa| 女同性一区二区三区人了人一 | 久久久精品国产一区二区三区| 欧美成人高清| 美玉足脚交一区二区三区图片| 国产精品白丝jk黑袜喷水| 亚洲第一黄网| 激情久久久久久久| 亚洲欧美影音先锋| 香蕉视频成人在线观看| 欧美午夜精品久久久久久人妖 | 国产精品户外野外| 亚洲肉体裸体xxxx137| 亚洲国产精品久久久久久女王| 午夜宅男欧美| 欧美在线网站| 国产午夜精品理论片a级探花 | 亚洲一区久久久| 午夜精品视频在线| 欧美日韩高清不卡| 日韩亚洲一区二区| 亚洲一区二区精品在线| 欧美日韩一区二区在线播放| 亚洲精品孕妇| 亚洲视频播放| 欧美体内she精视频在线观看| 亚洲精品日韩一| 亚洲欧美日韩区 | 99热精品在线| 欧美日韩第一区| 一本一道久久综合狠狠老精东影业 | 欧美精品激情| 久久久青草婷婷精品综合日韩| 国产日韩精品在线播放| 亚洲欧美制服另类日韩| 久久精品成人一区二区三区蜜臀| 国产嫩草一区二区三区在线观看| 亚洲欧美日韩国产成人| 久久久久青草大香线综合精品| 黄色欧美日韩| 欧美激情精品久久久久久蜜臀| 亚洲精品永久免费精品| 亚洲一区欧美激情| 国产亚洲福利社区一区| 久久午夜影视| 亚洲精品久久久久久久久久久| 在线视频欧美一区| 国产欧美在线观看一区| 久久久蜜桃精品| 亚洲国产精品高清久久久| 一本色道久久综合狠狠躁的推荐| 国产精品h在线观看| 午夜精品久久久久| 欧美成人自拍视频| 亚洲欧美日韩精品综合在线观看| 狠狠狠色丁香婷婷综合激情| 欧美精品久久一区二区| 亚洲欧美日韩精品久久奇米色影视| 久久亚洲一区二区| 在线亚洲观看| 黄色一区二区三区| 欧美午夜不卡在线观看免费| 久久精品官网| 99热在这里有精品免费| 欧美一级大片在线免费观看| 亚洲激情视频网站| 国产精品人人爽人人做我的可爱| 久久久久综合| 一本色道88久久加勒比精品| 你懂的国产精品| 欧美一区二区福利在线| 国产毛片久久| 欧美日韩一区精品| 嫩模写真一区二区三区三州| 欧美一级片在线播放| 亚洲毛片一区二区| 免费高清在线视频一区·| 欧美一级欧美一级在线播放| 亚洲激情不卡| 在线精品国精品国产尤物884a| 国产精品久久久久三级| 欧美日韩国产经典色站一区二区三区| 久久精品国产亚洲高清剧情介绍| 在线视频欧美日韩精品|