VC++在資源中載入紋理

來源:互聯網
上載者:User

Jeff Molofee(NeHe)的OpenGL教程Lesson: 38 Loading Textures From A Resource File & Texturing Triangles

歡迎來到NeHe教程第38課。離上節課的寫作已經有些時日了,加上寫了一整天的code,也許筆頭已經開始生鏽了

現在你已經學會了如何做方格貼圖,如何讀入bitmap及各種光柵映像...那麼如何做三角形貼圖,又如何在.exe檔案中體現你的紋理呢?

我每每被問及這兩個問題,可是一旦你看到他們是多麼簡單,你就會大罵自己居然沒有想到過

我不會事無巨細地解釋每一個細節,只需給你一些抓圖,就明白了。我將基於最新的code,請在首頁"NeHeGL I Basecode"下或者這張網頁最下面下載。

首先,我們把映像載入入資源檔。我向大家已經知道怎麼做了,只是,你忽略了幾步,於是值得到一些無用的資源檔。裡面有bitmap檔案,卻無法使用。

還記得吧?我們使用Visual C++ 6.0 做的。如果你使用其它工具,這頁教材關於資源的部分(尤其是那些圖)完全不適用。

* 暫時你只能用24bit BMP 映像。如果讀8bit BMP檔案要寫很多額外的code。我很希望聽到你們誰有更小的/更好的loader。我這裡的讀入8bit 和 24bit BMP 的code實在臃腫。用LoadImage就可以。

開啟檔案,點擊“插入”菜單,選“資源”

然後選擇你要插入的資源類型BITMAP檔案,單擊"插入"

然後是檔案視窗,進入DATA目錄,選中三個圖形檔案(用Ctrl啦)然後點“讀入”。注意檔案類型是否正確。

接下來會彈出三次警告(一個檔案一次),說讀入正確,但該檔案不能被瀏覽或編輯,因為它有多於256種顏色。沒什麼的!
一旦所有圖形都調入,將會出現一個列表。每個圖分配有一個ID,每個ID都是IDB_BITMAP打頭的,然後數字1-3。你要是懶得改,就不用管它了。不過我們還都比較勤快!

右健單擊每個ID,選"屬性",然後重新命名,使之與檔案名稱匹配。就像我圖片上那樣。

接下來,選“檔案--〉全部儲存”。你剛剛建立一個新的資源檔,所以Windows會問你取什麼名字。你隨便拉,也可以叫"lesson38.rc" , 然後儲存。

到此為止,你有了一個資源檔,裡面全是儲存在硬碟上的Bitmap 圖形檔案,要使用這些檔案,你還需要完成一系列步驟。

接下來該把資源檔加到你自己的項目裡面了。選“項目--〉添加到項目--〉檔案”

選擇resorce.h檔案和資源檔Lesson38.rc(用Ctrl)

最後確認資源檔Lesson38.rc放入RESOURCE FILES檔案夾。就像上面圖片裡那樣,點擊並拖入RESOURCE FILES檔案夾就好了。

移動之後選“檔案--〉全部儲存”,然後檔案部分就好了。好多的圖阿:)

然後我們開始code的部分。下面一段最重要的一行是#include "resource.h".沒有這行,編譯的時候就會有無數未定義變數的錯誤。resource.h檔案定義了資源檔裡的對象。所以要從IDB_BUTTERFLY1裡面讀取資料的話,最好include這個標頭檔 !

#include <windows.h>// Header File For Windows#include <gl\gl.h>         // Header File For The OpenGL32 Library#include <gl\glu.h>// Header File For The GLu32 Library#include <gl\glaux.h>// Header File For The GLaux Library#include "NeHeGL.h"// Header File For NeHeGL#include "resource.h"// Header File For Resource (*IMPORTANT*)#pragma comment( lib, "opengl32.lib" )// Search For OpenGL32.lib While Linking#pragma comment( lib, "glu32.lib" )        // Search For GLu32.lib While Linking#pragma comment( lib, "glaux.lib" )       // Search For GLaux.lib While Linking
#ifndef CDS_FULLSCREEN// CDS_FULLSCREEN Is Not Defined By Some#define CDS_FULLSCREEN 4// Compilers. By Defining It This Way,#endif// We Can Avoid ErrorsGL_Window*g_window;         
Keys*g_keys;
下面一段第一行分配三個紋理所需空間,接下來的結構體用於儲存關於約50個在螢幕上運動的物體的資訊。
tex將跟蹤每個物體所用紋理,x是物體的x座標,y是y座標,z,z座標,yi是一個隨機數用來控制物體下落速度,
spinz用來控制沿z軸的旋轉,spinzi是另一個隨機樹,記錄旋轉速度。flap用來控制物體的翅膀(一會在解釋這個)隨機數fi控制翅膀拍打的速度。 We create 50 instances of obj[ ] based on the object structure. 
// User Defined VariablesGLuint texture[3];// Storage For 3 Texturesstruct object// Create A Structure Called Object{int   tex;// Integer Used To Select Our Texturefloat x;// X Positionfloat y;// Y Positionfloat z;// Z Positionfloat yi;// Y Increase Speed (Fall Speed)float spinz;// Z Axis Spinfloat spinzi;// Z Axis Spin Speedfloat flap;// Flapping Triangles :)float fi;// Flap Direction (Increase Value)};
object obj[50];                     // Create 50 Objects Using The Object Structure
下面一段代碼是物體obj[loop]的初始化,loop從0到49(表示50個物體中的一個)。首先是隨機紋理從0到2表示
一個隨機著色的蝴蝶。x座標隨機的取-17.0f到+17.0f之間的值,y取18.0f,也就是從螢幕的上面一點點開始,
這樣一開始時看不到物體的。z也是-10.0f到-40.f之間的隨機數,spinzi取-1.0f到1.0f之間。flap取翅膀中心
位置,為0.0f。最後拍打速度fi和下落速度yi也是隨機的。
void SetObject(int loop)// Sets The Initial Value Of Each Object (Random){obj[loop].tex=rand()%3;// Texture Can Be One Of 3 Texturesobj[loop].x=rand()%34-17.0f;// Random x Value From -17.0f To 17.0fobj[loop].y=18.0f;// Set y Position To 18 (Off Top Of Screen)obj[loop].z=-((rand()%30000/1000.0f)+10.0f);// z Is A Random Value From -10.0f To -40.0fobj[loop].spinzi=(rand()%10000)/5000.0f-1.0f;// spinzi Is A Random Value From -1.0f To 1.0fobj[loop].flap=0.0f;// flap Starts Off At 0.0f;obj[loop].fi=0.05f+(rand()%100)/1000.0f;// fi Is A Random Value From 0.05f To 0.15fobj[loop].yi=0.001f+(rand()%1000)/10000.0f;// yi Is A Random Value From 0.001f To 0.101f}
 這回該到了最有意思的地方了。從資源檔中讀入bitmap,轉為紋理。hBMP是指向這個bitmap檔案的指標,
它將告訴我們的程式從哪裡讀取資料。BMP是一個bitmap結構體,我們把從資源檔中讀取的資料儲存在裡面。
第三行是告訴我們的程式我們將使用哪些ID:IDB_BUTTERFLY1,IDB_BUTTERFLY2,IDB_BUTTERFLY3。要用更多
的映像的話,只需增加資源檔中的映像,並在Texture[]中增加新的ID。   
 
void LoadGLTextures()// Creates Textures From Bitmaps In The Resource File{HBITMAP hBMP;// Handle Of The BitmapBITMAPBMP;// Bitmap Structure// The ID Of The 3 Bitmap Images We Want To Load From The Resource FilebyteTexture[]={ IDB_BUTTERFLY1, IDB_BUTTERFLY2, IDB_BUTTERFLY3 };
下面一行使用sizeof(Texture)來計算要建立多少個紋理。我們有3個ID,也就是3個紋理。
sizeof(Texture)也會在後面主迴圈中用到。   
glGenTextures(sizeof(Texture), &texture[0]);// Generate 3 Textures (sizeof(Texture)=3 ID’s)for (int loop=0; loop<sizeof(Texture); loop++)//Loop Through All The ID’s (Bitmap Images){ LoadImage需要如下參數:GetModuleHandle(NULL)-指向執行個體的控制代碼,MAKEINTRESOURCE(Texture[loop])-把Texture[loop]從整型轉為一個資
源值,也就是要讀的圖形檔案。IMAGE_BITMAP-告訴我們要讀的是一個bitmap檔案。 
接下來兩個參數(0,0)是讀入映像的高度和寬度像素數,使用預設大小就設為0。 
最後一個參數(LR_CREATEDIBSECTION)返回DIB section bitmap??這是一個沒有儲存顏色資訊的bitmap。也正是我們需要的。 
hBMP 指向從LoadImage()讀入的bitmap資料。      
  hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(Texture[loop]), IMAGE_BITMAP, 0, 0, 
LR_CREATEDIBSECTION);
    檢查指標hBMP是否有效,即指向有用資料。如果沒有指向任何資料,也可以彈出錯誤提示。 
如果資料存在,用GetObject()從hBMP取得資料(sizeof(BMP))並儲存在BMP中。 
glPixelStorei告訴OpenGL這些資料是以word alignments儲存的,也就是每像素4位元組。 
綁定紋理,設定濾波方式為GL_LINEAR_MIPMAP_LINEAR(又好又光滑),然後產生紋理。 
注意到我們使用BMP.bmWidth和BMP.bmHeight擷取映像的高度和寬度。並用GL_BGR_EXT交換紅藍,實際使用的資源資料是從BMP.bmBits中取得的
最後刪除bitmap對象,釋放所有與之相聯絡的系統資源空間。      
  if (hBMP)     // Does The Bitmap Exist?  {      // If So...   GetObject(hBMP,sizeof(BMP), &BMP); // Get The Object        // hBMP: Handle To Graphics Object        // sizeof(BMP): Size Of Buffer For Object Information        // Buffer For Object Information   glPixelStorei(GL_UNPACK_ALIGNMENT,4);  // Pixel Storage Mode (Word Alignment / 4 Bytes)   glBindTexture(GL_TEXTURE_2D, texture[loop]); // Bind Our Texture   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);  // Linear Filtering   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); // Mipmap Linear 
Filtering
   // Generate Mipmapped Texture (3 Bytes, Width, Height And Data From The BMP)   gluBuild2DMipmaps(GL_TEXTURE_2D, 3, BMP.bmWidth, BMP.bmHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, 
BMP.bmBits);   DeleteObject(hBMP);   // Delete The Bitmap Object  } }}
    init code沒有什麼新鮮的,只是增加了LoadGLTextures()調用上面的code。清屏的顏色是黑色,不進行深度檢測,這樣比較快。啟用紋理映
射和混色效果。      
BOOL Initialize (GL_Window* window, Keys* keys)          // Any GL Init Code & User Initialiazation Goes Here g_window = window; g_keys  = keys; // Start Of User Initialization LoadGLTextures();          // Load The Textures From Our Resource File  glClearColor (0.0f, 0.0f, 0.0f, 0.5f);  // Black Background glClearDepth (1.0f);    // Depth Buffer Setup glDepthFunc (GL_LEQUAL);   // The Type Of Depth Testing (Less Or Equal) glDisable(GL_DEPTH_TEST);   // Disable Depth Testing glShadeModel (GL_SMOOTH);   // Select Smooth Shading glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  // Set Perspective Calculations To Most Accurate glEnable(GL_TEXTURE_2D);    // Enable Texture Mapping glBlendFunc(GL_ONE,GL_SRC_ALPHA);   // Set Blending Mode (Cheap / Quick) glEnable(GL_BLEND);     // Enable Blending
    下面的迴圈緊接著初始化50個對象,不然它們會自己出現在螢幕中央相同的位置。      
 for (int loop=0; loop<50; loop++)   // Loop To Initialize 50 Objects {  SetObject(loop);    // Call SetObject To Assign New Random Values }
 return TRUE;      // Return TRUE (Initialization Successful)}
void Deinitialize (void)     // Any User DeInitialization Goes Here{}
void Update (DWORD milliseconds)    // Perform Motion Updates Here{ if (g_keys->keyDown [VK_ESCAPE] == TRUE)  // Is ESC Being Pressed? {  TerminateApplication (g_window);  // Terminate The Program }
 if (g_keys->keyDown [VK_F1] == TRUE)   // Is F1 Being Pressed? {  ToggleFullscreen (g_window);   // Toggle Fullscreen Mode }}
    接下來看看繪製代碼。在這部分我將講解如何用儘可能簡單的方式將一個映像映到兩個三角形上。有些人認為有理由相信,一個映像到三角形
上的單一映射是不可能的。 
實際上,你可以輕而易舉地將映像映到任何形狀的地區內。使得映像與邊界匹配或者完全不考慮形式。根本沒關係的。(譯者:我想作者的意
思是,從長方形到三角形的解析影射是不存在的,但不考慮那麼多的話,任意形狀之間的連續影射總是可以存在的。他說的使紋理與邊界匹配
,大概是指某一種參數化的方法,簡單地說使得扭曲最小。) 
首先清屏,迴圈潤色50個蝴蝶對象。      
void Draw (void)     // Draw The Scene{ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // Clear Screen And Depth Buffer
 for (int loop=0; loop<50; loop++)   // Loop Of 50 (Draw 50 Objects) {
    調用glLoadIdentify()重設投影矩陣,然後選擇對象的紋理。用glTranslatef()為蝴蝶定位,然後沿x軸旋轉45度。使之向觀眾微略傾斜,這
樣比較有立體感。最後沿z軸旋轉,蝴蝶就旋轉下落了。      
  glLoadIdentity ();      // Reset The Modelview Matrix  glBindTexture(GL_TEXTURE_2D, texture[obj[loop].tex]);  // Bind Our Texture  glTranslatef(obj[loop].x,obj[loop].y,obj[loop].z);  // Position The Object  glRotatef(45.0f,1.0f,0.0f,0.0f);    // Rotate On The X-Axis  glRotatef((obj[loop].spinz),0.0f,0.0f,1.0f);   // Spin On The Z-Axis
    其實到三角形上的映射和到方形上並沒有很大區別。只是你只有三個定點,要小心一點。 
下面的code中,我們將會值第一個三角形。從一個設想的方形的右上方開始,到左上方,再到左下角。潤色的結果像下面這樣: 
 
 
注意半個蝴蝶出現了。另外半個出現在第二個三角形裡。同樣地將三個紋理座標與頂點座標非別對應,這給出充分的資訊定義一個三角形上的
映射。      
  glBegin(GL_TRIANGLES);   // Begin Drawing Triangles   // First Triangle   glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);   // Point 1 (Top Right)   glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 1.0f, obj[loop].flap); // Point 2 (Top Left)   glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);   // Point 3 (Bottom Left)
    下面的code潤色另一半。同上,只是我們的三角變成了從右上到左下,再到右下。 
 
 
第一個三角形的第二點和第二個三角形的第三點(也就是翅膀的尖端)在z方嚮往複運動(即z=-1.0f和1.0f之間),兩個三角形沿著蝴蝶的身
體摺疊起來,產生拍打的效果,簡易可行。      
   // Second Triangle   glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);  // Point 1 (Top Right)   glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);  // Point 2 (Bottom Left)   glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f,-1.0f, obj[loop].flap); // Point 3 (Bottom Right)
  glEnd();        // Done Drawing Triangles
    下面一段通過從obj[loop].y中遞減obj[loop].yi使蝴蝶自上而下運動。spinz值遞增spinzi(可正可負)flap遞增fi.fi的正負取決於翅膀向
上還是向下運動。      
  obj[loop].y-=obj[loop].yi;  // Move Object Down The Screen  obj[loop].spinz+=obj[loop].spinzi; // Increase Z Rotation By spinzi  obj[loop].flap+=obj[loop].fi;  // Increase flap Value By fi
    當蝴蝶向下運行時,需要檢查是否越出螢幕,如果是,就調用SetObject(loop)來給蝴蝶賦新的紋理,新下落速度等。      
  if (obj[loop].y<-18.0f)   // Is Object Off The Screen?  {   SetObject(loop);  // If So, Reassign New Values  }    翅膀拍打的時候,還要檢查flap是否小於-1.0f或大於1.0f,如果是,令fi=-fi,以改變運動方向。Sleep(15)是用來減緩運行速度,每幀15毫
秒。在我朋友的機器上,這讓蝴蝶瘋狂的飛舞。不過我懶得改了:)      
  if ((obj[loop].flap>1.0f) || (obj[loop].flap<-1.0f)) // Time To Change Flap Direction?  {   obj[loop].fi=-obj[loop].fi;   // Change Direction By Making fi = -fi  } }
 Sleep(15);       // Create A Short Delay (15 Milliseconds)
 glFlush ();       // Flush The GL Rendering Pipeline}
    希望你在這一課學的開心。也希望通過這一課,從資源檔裡讀取紋理,和三角形映射的過程變得比較容易理解。我花五分鐘又沖讀了一遍,
感覺還好。如果你還有什麼問題,儘管問。我希望我的講義儘可能好,因此期待您的任何回應。
Jeff Molofee (NeHe)  
 * DOWNLOAD Visual C++ Code For This Lesson. * DOWNLOAD Borland C++ Builder 6 Code For This Lesson. ( Conversion by Christian Kindahl )* DOWNLOAD Code Warrior 5.3 Code For This Lesson. ( Conversion by Scott Lupton )* DOWNLOAD Dev C++ Code For This Lesson. ( Conversion by Warren Moore )* DOWNLOAD Game GLUT Code For This Lesson. ( Conversion by Alexandre Ribeiro de S?/a> )* DOWNLOAD LCC Win32 Code For This Lesson. ( Conversion by Robert Wishlaw )* DOWNLOAD Mac OS X/Cocoa Code For This Lesson. ( Conversion by Bryan Blackburn )* DOWNLOAD Visual Studio .NET Code For This Lesson. ( Conversion by Grant James )* DOWNLOAD Lesson 38 - Enhanced (Masking, Sorting, Keyboard - NeHe).* DOWNLOAD Lesson 38 - Screensaver by Brian Hunsucker.                       

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.