OpenGL speeds into the door
Author: Kehui Date: 2004-01-29 Read: 323 written 9CBS C / C base class version of a friend I do not know why, PM me recently to ask questions of people is more and more, I am really busy Nowadays, I have no time, I am doing the company's project, write my own procedure at home, hard to leave a little time to leave it to 9CBS ... people are really tired! But then, I don't have a good thing. I don't have a good thing. "WinAmp plug-in detailed explanation" may be a good job for many friends of our version, stickers are called good, also It is supported, and there are people who really take back to research. Many people are rushing to the 200. This time I will come to a simple, I believe this is also a very hot and interesting topic. According to the practice, I still have to say some nonsense, OpenGL is strictly defined as "a software interface to graphics hardware". From essentially, it is a 3D graphic and modeling library that is fully portable and very fast. With OpenGL, you can create a delicate and beautiful 3D graphics for visual quality approach the ray trace. The biggest benefit using OpenGL is that it is better than ray tracing. It uses algorithms that are well developed and optimized by Silicon Graphcs (SGI), which is recognized in computer graphics and animation. This is not to say that everyone should use OpenGL to paint pie charts and column charts for commercial applications. However, the appearance is very important, and the other features are substantially the same product, and its success or failure often depends on "attractive". And use beautiful 3D graphics to add a lot of attractions! This time I will take you into the real computer three-dimensional era and experience the charm of three-dimensional programming. We will start from OpenGL to start, start building a completely independent application, able to display some objects and add some special effects behind, so that our display screen is more beautiful. After reading this article, you should be able to write some simple three-dimensional applet, if you are a development veteran, then you may have a copyright belonging to your own 3D game? Although the starting point of this article is very low, you still need you to evaluate your actual programming ability: Skilled use VC.NET development environment and MSDN, write completely separate SDK programs, familiar with C language and C . Please keep a happy mood reading full text. First let VC.Net automatically build a running SDK program (this should you?), The name is GLTEST, then learn about the header file and import library we need to use. Generally in VC.NET, OpenGL's header file is stored in the subdirectory GL stored in the system header file, so specify a relative path when specified. Gl.h is the basic header file, glu.h is the application header file, and most applications need to include both headers. OpenGL32.lib is the standard import library of OpenGL's WIN32 implementation, so we add the following compiler instructions in the header file declaration area of Stdafx.cpp in the project that has just been established: #pragma comment (Lib, "OpenGL32.LIB") #pragma comment (lib, "glu32.lib") #include
If you are an initiator, I hope to get the knowledge you want from the OpenGL of MSDN, then I can only tell you, you are wrong, you should buy a "OpenGL Programming Authoritative Guide" in the bookstore, this There is really something that is really suitable for you. Now you may disdain for me, because you will not spend too much energy and money in studying this type of "boring and useless things", just watching this article to pick it, it doesn't matter, you Now I have to do patient, continue to read all the text. We also need to make some modifications to the project auto-generated by VC.Net, let it fit our OpenGL app. The first thing to change is the message loop. Most time rendered applications will put the code of the drawing in the idle event. The idle event is not so much a kind of incident, it is better to say that it is "no incident", look at it first. How do we write a message loop: While (True) {if (PEEKMESSAG, NULL, 0, 0, PM_REMOVE)) {if (! TranslateAccelerator (Msg.hwnd, HaccelTable, & MSG) {TranslateMessage (& MSG); DispatchMessage (& MSG); DispatchMessage },},}} If (wm_quit == msg.MESSAGE) {Break;} onder ();} Using PeekMessage instead of getMessage, this will not wait when there is no message in the message queue, which is returned to a false value, so We may know that the current application processes the idle state. It is also worth noting that if the result is WM_QUIT, PeekMessage will return false values, so we need to do some special processing. At the last call to our idle message processing function: onIdle (); the second to change the registration form class, Wcex.Style should be assigned 0, because this is a real-time rendering program, does not need the system Automatically manage the reload of the form, which can improve the speed of the program. The third part to change is to block the message processing callback function to the WM_PAINT message processing, use the default Return DefWindowProc (Hwnd, Message, WPARAM, LPARAM); OK, or if the GDI's drawing will conflict with OpenGL And prevent the program idle. Next is the most important part, initialize our OpenGL. First, step out: 1. Get the device environment (DC) you need to draw above; Second, set pixel formats for the device environment; 3, create OpenGL devices based on the device environment; four, initialize OpenGL drawing scenes and status Set.
Here we look at the first three steps of the code: g_hDC = GetDC (g_hWnd); // get DCPIXELFORMATDESCRIPTOR pfd; ZeroMemory (& pfd, sizeof (PIXELFORMATDESCRIPTOR)); // unrelated items set 0pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; // version number, must be 1pfd.dwflags = pfd_draw_to_window | pfd_support_opengl | pfd_doublebuffer; // Two must, PFD_Doublebuffer specifies the use of double buffer pfd.ipixeltype = pfd_type_rgba; // color format is red, green, blue, transparent Pfd.ccolorBits = 24; // 24 bit color deep pfd.cdepthbits = 32; // 32-bit Z buffer depth setpixelformat (g_hdc, choosepixelformat (g_hdc, & pfd), & pfd); // Select a pixel format, and set to DC G_glres = wglcreateContext (g_hdc); // Create OpenGL device WGLmakecurrent (g_hdc, g_glres); // Enable OpenGL device to see the above code and annotation, you should know the role of each statement, is it simple? But don't forget, release OpenGL resources when the WM_DESTROY message is triggered: releasedc (g_hwnd, g_hdc); WGLDeleteContext (g_glres); so OpenGL is completed by initialization, this means you can use OpenGL statement in OnIdle immediately Although theory is theoretical, in order to achieve our effect - a rotating square box - we also need to set up the scene: glenable (gl_cull_face); // will not render the invisible hidden face GLCULLFACE (GL_BACK ); Glenable (GL_Depth_test); // Whether the origination is rear, the distance from the distance is always behind the nearby object.
GLDEPTHFUNC (GL_LEQUAL); int Lightpos [] = {50, 50, 10, 1}; // The last specified this is a poised point light source float lightcolor [] = {0.3F, 0.3F, 0.3F, 1.0F }; // 1.0 is the brighter, 0.3 looks not so glare glenable (GL_Lighting); // Turn on the light state unless the person changes, the state will always reserve the program to exit GLLightiv (GL_Light0, GL_Position, Lightpos); // Set the light position GLLIGHTFV (GL_LIGHT0, GL_AMBIENT, LIGHTCOLOR); // Environmental color GLLIGHTFV (GL_LIGHT0, GL_DIFFUSE, LIGHTCOLOR); // Scattered color glenable (GL_Light0); // Open the first source, you can open 8 Glenable ( GL_COLOR_MATERIAL); // open color material glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // we can specify the color of the object glShadeModel (GL_SMOOTH); // enable smooth colored glClearColor (255.0f / 255.0f, 255.0f / 255.0f, 200.0f / 255.0f, 0.0); // background color glcolor3ub (140, 200, 255); // Fill color here to take a slightly mentioned that OpenGL is a state machine mode, such as opening a state with Glenable, afterwards This state will always be retained and applied, unless you call GLDISABLE and the same type of function to change the status or program exit. The vast majority of OpenGL is a state machine. For example, you set the current texture, then texture will not change automatically. Let's talk about some theories, please don't be bored, because if there is no such knowledge, our three-dimensional tutorial will be difficult to go. In order to facilitate spatial transform operations of objects, translation, scaling such as 3D scenarios, we introduce the concept of a three-dimensional transform matrix. This is a 4x4 matrix, and of course the value on the diagonal of the unit matrix is 1. Look at this seemingly ordinary matrix, there is countless magical. For example, there is a spatial point in the Cartesian coordinate system, the coordinates are 10, 10, 10, now you want to pan 5, -2, 8 units, then you only need to convert the top three columns of the last line of the transformation matrix The value is that the coordinates of the spatial point are the coordinates of the space point as a 4x1 matrix, and the last column will be re-exchanged with the conversion matrix (what? You don't think of the matrix ?! I fell!) The first three columns of the 4x1 matrix obtained are X, Y, and Z transformed spatial point coordinates. The same rotation, scaling is also a general method, and the difference is only the value of different locations in the transform matrix represents different meaning.
Now we will start drawing. Determine the perspective first:
/ / Set the model matrix void setModalMatrix (void) {GlmatrixMode (GL_ModelView); GLLoadIdentity (); // Unit matrix // This function is called in the OnIdle, so we use the following code to implement the rotation of the object / / A concept that is easy to understand is that you turn around the object to the object to switch in some simple scenes, so we look through the matrix operation, let the eye point in a certain height. movement. Knowing the simplified equation of the circle is: (sinα * r) ^ 2 (COSα * R) ^ 2 = r ^ 2, so code // is very well understood. Static float fradius = 0; fRADIUS = 0.01F; if (FRADIUS> M_PI * 2) {FRADIUS = 0;} Glulookat (COSF (FRADIUS) * 30, SINF (FRADIUS) * 30, 15.0, 0.0, 0.0, 0.0, / / See 0.0, 0.0, 1.0); // Set the direction of the eye (camera), the vector represents the eye table up} // set the perspective matrix Void setProjmaMatrix (Word Word WHEIGHT) {// The function will be called when WM_SIZE, so you should set GLVIEWPORTGLVIEWPORT (0, 0, wwidth, wheight); GLmatrixMode (GL_Projection); GLLoadIdentity (); // This is very similar to the image, the first parameter sets the camera wide angle The second parameter is a long width ratio, and the back is far clipping. Gluperspective (45.0, (Double) WWIDTH / (Double) Wheight, 1.0, 1000.0);
Then we call the following code in OnDraw:
// First rendezed the residue of the last rendering to the background color glclear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); Glbegin (GL_QUADS); // Setting the drawing mode, we draw a flat quadrilateral Glvertex2i (5, 5); GlvertEX2i (5, - 5); GLVERTEX2I (-5, -5); Glvertex2i (-5, 5); swapBuffers (g_hdc); // Switch before and after buffering, double buffer no flash
At this point, the code in GLTEST.CPP is like this:
// gltest.cpp: Define the entry point of the application. //
#include "stdafx.h" #include "glteest.h" #define max_loadstring 100
// Global variable: hinstance hinst; // Current instance hWnd g_hwnd; HDC g_hdc; hglrc g_glres;
TCHAR SZTITLE [MAX_LOADSTRING]; // Title Bar Text Tchar SzWindowClass [MAX_LOADSTRING]; // Main Window Category Name
The forward declaration of the function contained in this code module: void oncreate (hwnd hwnd); void ondestroy (void); void ondraw (void); void setProjmatrix (Word Word Wordth, Word Wheight); void SetModalMatrix (void); Void OnIdle (Void);
ATOM MyRegisterClass (HINSTANCE hInstance); BOOL InitInstance (HINSTANCE, int); LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About (HWND, UINT, WPARAM, LPARAM); int APIENTRY _tWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance LPTSTR LPCMDLINE, INT NCMDSHOW) {// TOD places this code. Msg msg; Haccel HaccelTable;
// Initialize the global string LoadString (Hinstance, IDs_App_title, sztitle, max_loadstring); LoadString (Hinstance, IDC_GLTEST, SZWINDOWCLASS, MAX_LOADSTRING); MyRegisterClass (Hinstance);
// Perform an application initialization: if (! Initinstance (hinstance (ncmdshow)) {Return False;}
Hacceltable = loadingAccelerators (Hinstance, (lpctstr) IDC_GLTEST);
// Principal Message Cycle: While (True) {IF (PEEKMESSAGE (& MSG, NULL, 0, 0, PM_Remove) {if (! TranslateAccelerator (Msg.hwnd, Hacceltable, & MSG) {TranslateMessage (& MSG); DispatchMessage (& MSG); DispatchMessage );},} If (wm_quit == msg.MESSAGE) {Break;} onidle ();
Return (int) msg.wparam;}
//// Function: myregisterclass () //// Destination: Register window classes. //// Note: /// The code only needs this function and its usage when this code is compatible with Win32 system before you want to add the WINDOWS 95 function. Call this function // is very important, so that the application can get the associated // "formatted" small icon. // atom myregisterclass (hinstance hinstance) {WNDCLASSEX WCEX;
Wcex.cbsize = sizeof (wndclassex);
wcex.style = 0; wcex.lpfnWndProc = (WNDPROC) WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon (hInstance, (LPCTSTR) IDI_GLTEST); wcex.hCursor = LoadCursor (NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW 1); wcex.lpszMenuName = (LPCTSTR) IDC_GLTEST; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon (wcex.hInstance, (LPCTSTR) IDI_SMALL Return RegisterClassex (& WCEX);
/// / Function: InitInstance (Handle, Int) //// Purpose: Save the instance handle and create a main window //// Note: /// In this function, we save the instance handle in the global variable and / / Create and display the main program window. // Bool InitInstance (Hinstance Hinstance, INT NCMDSHOW) {hinst = hinstance; // Store instance handles in global variables
CreateWindow (Szwindowclass, Sztitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, HINSTANCE, NULL);
IF (! g_hwnd) {Return False;} oncreated ();
ShowWindow (g_hwnd, ncmdshow); UpdateWindow (g_hwnd);
Return True;}
LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {int wmId, wmEvent; switch (message) {case WM_CREATE: OnCreate (hWnd); break; case WM_COMMAND: wmId = LOWORD (wParam); wmEvent = HIWORD (WPARAM); // Analysis Menu Selection: Switch (WMID) {CASE IDM_ABOUT: DialogBox (Hinst, (LPCTSTSTSTR) IDD_ABOUTBOX, HWND, (DLGPROC); Break; Case IDM_EXIT: DESTROYWINDOW (HWND); break; default: return DefWindowProc (hWnd, message, wParam, lParam);} break; case WM_SIZE: SetProjMatrix (LOWORD (lParam), HIWORD (lParam)); break; case WM_DESTROY: OnDestroy (); PostQuitMessage (0); break; default: return DefWindowProc (hwnd, message, wparam, lparam);} Return 0;
// Message handler on the "About" box. LRESULT CALLBACK About (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {switch (message) {case WM_INITDIALOG: return TRUE; case WM_COMMAND: if (LOWORD (wParam) == IDOK || LOWORD (wParam) == IDCANCEL) {EndDialog (HDLG, Loword (WPARAM)); Return True;} Break;} Return False;
Void oncreate (hwnd hwnd) {g_hwnd = hwnd;}
Void OnDestroy (void) {releasedc (g_hwnd, g_hdc); WGLDeleteContext (g_glres);}
void OnCreated (void) {g_hDC = GetDC (g_hWnd); PIXELFORMATDESCRIPTOR pfd; ZeroMemory (& pfd, sizeof (PIXELFORMATDESCRIPTOR)); pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER ; pfd.ipixeltype = pfd_type_rgba; pfd.ccolorbits = 24; pfd.cdepthbits = 32;
Setpixelformat (g_hdc, choosepixelformat (g_hdc, & pfd), & pfd);
g_glres = wglcreateContext (g_hdc); WGLmakecurrent (g_hdc, g_glres);
GLENABLE (GL_CULL_FACE); GLCULLFACE (GL_BACK);
Glenable (GL_DEPTH_TEST); GLDEPTHFUNC (GL_LEQUAL);
INT LIGHTPOS [] = {50, 50, 10, 1}; float lightcolor [] = {0.3F, 0.3F, 0.3F, 1.0F};
glEnable (GL_LIGHTING); glLightiv (GL_LIGHT0, GL_POSITION, LightPos); glLightfv (GL_LIGHT0, GL_AMBIENT, LightColor); glLightfv (GL_LIGHT0, GL_DIFFUSE, LightColor); glEnable (GL_LIGHT0); glEnable (GL_COLOR_MATERIAL); glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
Glshademodel (GL_SMOOTH);
GlclearColor (255.0F / 255.0F, 255.0F / 255.0F, 200.0F / 255.0F, 0.0); GLCOLOR3UB (140, 200, 255);
Void OnDraw (Void) {GL_CLOR_BUFFER_BIT | GLBEGIN (GL_QUADS); // Setting the drawing mode, we draw a flat four-sided Glvertex2i (5, 5); GlvertEX2i (-5, 5); GlvertEX2i (-5, -5); GLVERTEX2I (5, -5); glend (); swapbuffers (g_hdc); // Switch front and rear buffer, double buffer no flash} Void setModalMatrix (void) {GLmatrixMode (GL_ModelView); gLloadIdentity (); static float fradius = 0; FRADIUS = 0.01F; IF (FRADIUS> M_PI * 2) {FRADIUS = 0;} Glulookat (COSF (FRADIUS) * 30, SINF (FRADIUS) * 30, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 , 1.0);
void SetProjMatrix (WORD wWidth, WORD wHeight) {glViewport (0, 0, wWidth, wHeight); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (45.0, (double) wWidth / (double) wHeight, 1.0, 1000.0);}
Void onder (void) {setModalMatrix (); onDraw ();
Now the program can run, tell me what you saw? It should be a rotating plane quadrangular shape. Did you see anything? Please review the procedure you write above, see if every sentence is like me. If you still don't get resolved, you can send a short message to me to get a chance to get help. But please note that I will not answer every stupid question. For example, please don't ask me why your form creates can't be created or the vc.net downloads.
Of course, I just said that we have to draw a cube box, I certainly have not forgotten, just before this, I want more readers to familiarize with OpenGL's drawing mechanism. Other square box is very simple, we should have such a set of data, and do it as global variables. Each vertex is represented by x, y, and z three-dimensional short, one eight vertices, can you follow these data to hand painting a square from the paper?
Short nsrcbox [3 * 8] = {5, 5, 0, 5, 5, 10, 5, 5, 0, 5, -5, 10, 5, 5, 0, -5, -5, 10 , -5, 5, 0, -5, 5, 10,};
When drawing, we can draw a triangular painting in a triangle, or like a quad-shaped four-sided painting, but in order to tell some of the Triangular paintings. Each face consists of two triangles, a total of six faces, twelve triangles. If you numbered the eight vertices above 0-7, then we can paint in this order:
0, 4, 6, 0, 2, 4, 0, 6, 7, 0, 7, 1, 0, 3, 2, 0, 1, 3, 5, 2, 3, 5, 4, 2, 5, 6, 4, 5, 7, 6, 5, 1, 7, 5, 3, 1,
Here, it is necessary to pay attention to the right hand, in OpenGL, in the order of drawing a triangular three-dimensional top, with the right hand is being in the triangle, the direction of the octa is the positive direction of this surface. In fact, you have already understood what the index array is unknowing, that is, the number above, we save them, be a global variable: byte byindex [36] = {0, 4, 6, 0, 2, 4, 0, 6, 7, 0, 7, 1, 0, 3, 2, 0, 1, 3, 5, 2, 3, 5, 4, 2, 5, 6, 4, 5, 7, 6, 5, 1, 7, 5, 3, 1,};
Ok, now I'm not worthy of Dongfeng, how to paint? Maybe you will think of calling one of the Glvertex as the above program, is it, yes, you are correct, but it's too slow and too complicated, how many GlvertEX do you have to write? Fortunately OpenGL provides us with a convenient drawing mechanism: array draws. In the bottom of the initialization code, add such a statement to specify the array of vertices:
GlenableClientState (GL_VERTEX_ARRAY); // Enable vertex array GlvertExPointer (3, GL_SHORT, 0, NSRCBOX); // Set the vertex array address
Then add this sentence between Clear and SWAP on DrawRaw:
// After two parameters specify the type and array address of the index number value value, GLDRAWELEMENTS (GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, BYINDEX);
You should be able to see a rotating cube, but it is still chaos, can't see the corner, this is because you don't specify the direction of the light reflection, the following we will introduce a concept "method vector". In real life, human eye seeing objects is due to the reflection of the object, if the object does not reflect light, or does not reflect in the eye direction of the human eye, the human eye will consider that this object is not illuminated. Do not refer to reflection, the incident angle of the object reflected in each mirror is equal, so that the method of the mirror reflective object is perpendicular to the plane. Due to the particle of light, the diffuse reflective object we can consider a complex object consisting of infinite plurality of specular reflective objects. Based on these theories, OpenGL will calculate the brightness of this surface in accordance with a given vertex method to the given vertex method. The calculation vector is used to use a mathematical basis, which may be difficult to understand for some people, but there is no relationship. Here there is a ready-made function. You can calculate directly:
// Normalization functions, there is nothing to say, Template
IF (FLEENGTH, 0.0, 1E-8)) {DLENGTH = 1.0;} PVector [0] / = (TYPE) DLENGTH; PVector [1] / = (TYPE) DLENGTH; PVector [2] / = (TYPE) DLENGTH; RETURN S_OK;
// The first parameter indicates a triangular shape with 9 Double, and the triangular method will be out of the second parameter. Template
For (int i = 0; i <36; i ) {// ntempbox is a temporary array variable for saving the outgoing data. MoveMemory (& ntempbox [i * 3], & nsrcbox [byindex [i] * 3], sizeof (NTEMPBOX [0]) * 3);
Below we can calculate the normal vector.
For (int i = 0; i <12; i ) {// calculate the triangle method of the triangle with three vertices of a triangle CalcNormal (& ntempbox [i * 9], & fnormal [i * 9]); // And put this approach to the three vertices of this triangle MoveMemory (& Fnormal [i * 9 3], & fnormal [i * 9], sizeof (FNORMAL [0]) * 3); MoveMemory (& Fnormal [i * 9 6], & fNormal [i * 9], sizeof (fNormal [0]) * 3);} glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (3, GL_SHORT, 0, nTempBox); glEnableClientState (GL_NORMAL_ARRAY); // enable normal vector glNormalPointer ( GL_FLOAT, 0, FNORMAL); // Fill in the method vector array address
Because you don't need the index group, the following drawing code will be simpler:
GLDRAWARRAYS (GL_TRIANGLES, 0, 36);
Ok, now the whole code should be this:
// gltest.cpp: Define the entry point of the application. //
#include "stdafx.h" #include "glteest.h" #define max_loadstring 100
// Global variable: hinstance hinst; // Current instance hWnd g_hwnd; HDC g_hdc; hglrc g_glres;
Short nsrcbox [3 * 8] = {5, 5, 0, 5, 5, 10, 5, 5, 0, 5, -5, 10, 5, 5, 0, -5, -5, 10 , -5, 5, 0, -5, 5, 10,}; Byte Byindex [36] = {0, 4, 6, 0, 2, 4, 0, 6, 7, 0, 7, 1, 0, 3, 2, 0, 1, 3, 5, 2, 3, 5, 4, 2, 5, 6, 4, 5, 7, 6, 5, 1, 7, 5, 3, 1,})
Short ntempbox [36 * 3]; float fnormal [36 * 3];
TCHAR SZTITLE [MAX_LOADSTRING]; // Title Bar Text Tchar SzWindowClass [MAX_LOADSTRING]; // Main Window Category Name
Template
IF (FLEENGTH, 0.0, 1E-8)) {DLENGTH = 1.0;} PVector [0] / = (TYPE) DLENGTH; PVector [1] / = (TYPE) DLENGTH; PVector [2] / = (TYPE) DLENGTH; RETURN S_OK;
Template
The forward declaration of the function contained in this code module: void oncreate (hwnd hwnd); void ondestroy (void); void ondraw (void); void setProjmatrix (Word Word Wordth, Word Wheight); void SetModalMatrix (void); Void OnIdle (Void);
ATOM MyRegisterClass (HINSTANCE hInstance); BOOL InitInstance (HINSTANCE, int); LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About (HWND, UINT, WPARAM, LPARAM); int APIENTRY _tWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance LPTSTR LPCMDLINE, INT NCMDSHOW) {// TOD places this code. Msg msg; Haccel HaccelTable;
// Initialize the global string LoadString (Hinstance, IDs_App_title, sztitle, max_loadstring); LoadString (Hinstance, IDC_GLTEST, SZWINDOWCLASS, MAX_LOADSTRING); MyRegisterClass (Hinstance);
// Perform an application initialization: if (! Initinstance (hinstance (ncmdshow)) {Return False;}
Hacceltable = loadingAccelerators (Hinstance, (lpctstr) IDC_GLTEST);
// Principal Message Cycle: While (True) {IF (PEEKMESSAGE (& MSG, NULL, 0, 0, PM_Remove) {if (! TranslateAccelerator (Msg.hwnd, Hacceltable, & MSG) {TranslateMessage (& MSG); DispatchMessage (& MSG); DispatchMessage );},} If (wm_quit == msg.MESSAGE) {Break;} onidle ();
Return (int) msg.wparam;}
Atom myregisterclass (hinstance hinstance) {WNDCLASSEX WCEX;
Wcex.cbsize = sizeof (wndclassex);
wcex.style = 0; wcex.lpfnWndProc = (WNDPROC) WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon (hInstance, (LPCTSTR) IDI_GLTEST); wcex.hCursor = LoadCursor (NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW 1); wcex.lpszMenuName = (LPCTSTR) IDC_GLTEST; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon (wcex.hInstance, (LPCTSTR) IDI_SMALL );
Return RegisterClassex (& WCEX);
/// / Function: InitInstance (Handle, Int) //// Purpose: Save the instance handle and create a main window //// Note: /// In this function, we save the instance handle in the global variable and / / Create and display the main program window. // BOOL InitInstance (HINSTANCE hInstance, int nCmdShow) {hInst = hInstance; // instance handle is stored in global variables CreateWindow (szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL) ;
IF (! g_hwnd) {Return False;} oncreated ();
ShowWindow (g_hwnd, ncmdshow); UpdateWindow (g_hwnd);
Return True;}
/// Function: WndProc (HWND, Unsigned, Word, LONG) //// Destination: Handling the message of the main window. //// WM_COMMAND - Processing Application Menu // WM_Paint - Draws Main Window // WM_DESTROY - Send Exit Messages and Returns /// Lresult Callback WndProc (HWND HWND, UINT Message, WPARAM WPARAM, LPARAM LPARAM) {Int Wmid, wmEvent; switch (message) {case WM_CREATE: OnCreate (hWnd); break; case WM_KEYDOWN: g_bStartSwap = g_bStartSwap; break; case WM_MOVE:! SetWindowText (g_hWnd, "Move"); break; case WM_COMMAND: wmId = LOWORD (wParam) WMEVENT = HiWord (WPARAM); // Analysis Menu Selection: Switch (WMID) {Case IDM_About: DialogBox (Hinst, (Lpctstr) IDD_ABOUTBOX, HWND, (DLGPROC); Break; Case IDM_EXIT: DestroyWindow (hwnd); BREAK ; default: return DefWindowProc (hWnd, message, wParam, lParam);} break; case WM_SIZE: SetProjMatrix (LOWORD (lParam), HIWORD (lParam)); break; case WM_DESTROY: OnDestroy (); PostQuitMessage (0); break; Default: Return DefWindowProc (Hwnd, Message, WPARAM, LPARAM);} Return 0;
// Message handler on the "About" box. Lresult Callback About (HWND HDLG, UINT MESSAGE, WPARAM WPARAM, LPARAM LPARAM) {Switch (Message) {Case WM_INITDIALOG: RETURN TRUE
Case WM_COMMAND: IF (WPARAM) == iDok || loword (wparam) == idcancel) {enddialog (hdlg, loword (wparam)); return true;} Break;} returnaf false;} void oncreate (hwnd hwnd) {g_hwnd = hwnd;}
Void OnDestroy (void) {releasedc (g_hwnd, g_hdc); WGLDeleteContext (g_glres);}
Void oncreated (void) {g_hdc = getdc (g_hwnd);
PIXELFORMATDESCRIPTOR pfd; ZeroMemory (& pfd, sizeof (PIXELFORMATDESCRIPTOR)); pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; Pfd.cdepthbits = 32;
Setpixelformat (g_hdc, choosepixelformat (g_hdc, & pfd), & pfd);
g_glres = wglcreateContext (g_hdc); WGLmakecurrent (g_hdc, g_glres);
GLENABLE (GL_CULL_FACE); GLCULLFACE (GL_BACK);
Glenable (GL_DEPTH_TEST); GLDEPTHFUNC (GL_LEQUAL);
INT LIGHTPOS [] = {50, 50, 10, 1}; float lightcolor [] = {0.3F, 0.3F, 0.3F, 1.0F};
glEnable (GL_LIGHTING); glLightiv (GL_LIGHT0, GL_POSITION, LightPos); glLightfv (GL_LIGHT0, GL_AMBIENT, LightColor); glLightfv (GL_LIGHT0, GL_DIFFUSE, LightColor); glEnable (GL_LIGHT0); glEnable (GL_COLOR_MATERIAL); glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
Glshademodel (GL_SMOOTH);
GlclearColor (255.0F / 255.0F, 255.0F / 255.0F, 0.0); for (int i = 0; i <36; i ) {MoveMemory (& ntempbox [i * 3], & nsrcbox [byindex [ I] * 3], SIZEOF (NTEMPBOX [0]) * 3);} for (int i = 0; i <12; i ) {CalcNormal (& ntempbox [i * 9], & fnormal [i * 9]); MoveMemory (& Fnormal [i * 9 3], & fnormal [i * 9], sizeof (FNORMAL [0]) * 3); MoveMemory (& FNORMAL [i * 9 6], & Fnormal [i * 9], SIZEOF (FNORMAL [ 0]) * 3);} glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (3, GL_SHORT, 0, nTempBox); glEnableClientState (GL_NORMAL_ARRAY); glNormalPointer (GL_FLOAT, 0, fNormal); glColor3ub (140, 200, 255);}
Void OnDraw (Void) {GL_CLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLDRAWARRAYS (GL_TRIANGLES, 0, 36); swapBuffers (g_hdc);
void SetModalMatrix (void) {glMatrixMode (GL_MODELVIEW); glLoadIdentity (); static float fRadius = 0; fRadius = 0.01f; if (fRadius> M_PI * 2) {fRadius = 0;} gluLookAt (cosf (fRadius) * 30, SINF (FRADIUS) * 30, 15.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
void SetProjMatrix (WORD wWidth, WORD wHeight) {glViewport (0, 0, wWidth, wHeight); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (45.0, (double) wWidth / (double) wHeight, 1.0, 1000.0);}
Void onder (void) {setModalMatrix (); onDraw ();
Now that we have achieved the effect we want, is it very pleasant? The next article is entitled to Direct3D, so stay tuned.
Creamdog completed at 2:46 in the morning of September 20, 2003