Write to the CBS C / C basic class version? I don't know why, people who have sent me a short message questioning questions are more and more, I am really a bit busy, now a little personal time is not. In the company's project, write your own procedures at home, hard to leave a little time to stay to CBS ... people live 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.
??? I still have to say some nonsense in accordance with the practice, 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 SDK program that can run (this should be?), The name is GLTest, then come to find out 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
#include
After this, you can call the OpenGL's function at will. However, it has to be told that there is a definition of the OpenGL standard function in the MSDN included with VC.NET, but only this is far from DirectX's tutorial. From this point you can see that Microsoft is a force in the big business strategic approach to advocating DirectX, excluding other graphic programming interfaces. 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 (PeekMessage (& MSG, NULL, 0, 0, PM_REMOVE))? {?? if (! TranslateAccelerator (msg.hWnd, HaccelTable, & MSG)) ?? {?? TRANSLATEMESSAGE (& MSG); ??? DISPATCHMESSAGE (& MSG); ??} ?? Continue;?}? If (wm_quit == msg.MESSAGE)? {?? Break;?}? Onidle ();}
??? Using PeekMessage instead of getMessage, it will not wait for a false value when there is no message in the message queue, 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 Set. Let's take a look at the first three steps:
g_hDC = GetDC (g_hWnd); ?? // Get DCPIXELFORMATDESCRIPTOR pfd; ZeroMemory (& pfd, sizeof (PIXELFORMATDESCRIPTOR)); ?? // entry is set independent 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
??? After reading the code and comment above, you should be very clear that every statement is, 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);
Such OpenGL will be completed by initialization. This means you can immediately use the OpenGL statement to draw in OnIdle, although theore is theore, but in order to achieve our effect - a rotating square box - we still need Set up the scene again:
GLENABLE (GL_CULL_FACE); // will not render the invisible hidden face GLCULLFACE (GL_BACK);
Glenable (GL_DEPTH_TEST);? // No matter the resequential, the distance from the distance is always behind the adjacent object. GLDEPTHFUNC (GL_LEQUAL);
INT LIGHTPOS [] = {50, 50, 10, 1};? // The last specified this is a pointless 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 GlcolormaTerial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);? // We can specify color glshademodel (GL_SMOOTH) for objects;? // Enable smooth color GlclearColor (255.0f / 255.0f 255.0F / 255.0F, 200.0F / 255.0F, 0.0);? // background color glcolor3ub (140, 200, 255); ?? // Fill color ??? Here you have to take a slight one is OpenGL is one A state machine mode, such as you open a state with Glenable, will always reserve and apply this status in the later drawing, unless you call the GLDISABLE and the same 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 do. 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? // An easy understanding concept is that you turn around the object to the object itself in some simple scenes? // The effect looks like, so we pass the matrix operation to make the eyes Be a height to do a round week? //. 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 means the eye table up} // setting the perspective matrix void SetProjMatrix (WORD wWidth, WORD wHeight) {? // this function is called when WM_SIZE, so it should set about glViewPort? glViewport (0, 0, wWidth, wHeight) ;? glMatrixMode (GL_PROJECTION) ;? glLoadIdentity ( );? // This is similar to the image, the first parameter sets the camera wide angle, and the second parameter is a long width ratio, which is far clipping. Gluperspective (45.0, (double) WWIDTH / (DOUBLE) WHEIGHT, 1.0, 1000.0);}
??? Then we call the following code in the onDraw:
// First, the last rendered residue is the background color glclear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLBEGIN (GL_QUADS); ?? // Set the drawing mode, we draw a flat quadrilateral Glvertex2i (5, 5); Glvertex2i (5) , -5); GlvertEX2i (-5, -5); GlvertEX2i (-5, 5); swapBuffers (g_hdc); ?? // Switch front and rear buffer, double buffer no flash
??? To this, 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 class 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, ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? Lptstr ??? lpcmdline, ???????????????????? INT ?????? ncmdshow) {?? // Todo: Place the code here. ? 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 = loadAccelerators (Hinstance, (LPCTSTR) IDC_GLTEST);
? // Principal message loop:? While (TRUE)? {?? IF (PEEKMESG, NULL, 0, 0, PM_REMOVE)) ?? {??? if (! TranslateAccelerator (msg.hwnd, HaccelTable, & MSG) ) ??? {???? translateMessage (& msg); ???? DispatchMessage (& msg); ???} ??? continue; ??} ?? if (wm_quit == msg.MESSAGE) ?? {? ?? Break; ??} ?? onidle () ;?}
Return (int) msg.wparam;}
?
/ / / /? Function: myregisterclass () ///? Purpose: Register window classes. ////? Note: //// ??? When you want to be compatible with Win32 system before you want to add to the Windows 95 function, //??? Function and its usage. Call this function // ??? is very important, so that the application can get the associated //? "" Format "small icon. // atom myregisterclass (hinstance hinstance) {? WNDCLASSEX WCEX;
Wcex.cbsize = sizeof (WNDCLASSEX);
? wcex.style ??? = 0;? wcex.lpfnwndproc? = (wcex.cbclsextra ?? = 0; wcex.cbwndextra ?? = 0; wcex.hinstance ?? = hinstance;? wcex .hicon ??? = loadicon (Hinstance, (LPCTSTSTR) IDI_GLTEST);? wcex.hcursor ?? = loadcursor (null, idc_arrow) ;? wcex.hbrbackground? = (Hbrush) (color_window 1);? wcex.lpsz GenenaME? = (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 the main window //// ?? Note: //// ??????? here In the 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 the instance handle in the global variable
?? 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 (wmEvent = half; ?? // analysis menu selection: ?? Switch (wmid) ?? {?? case idm_about: ??? Dialogbox (hinst, LPCTSTSTR) IDD_ABOUTBOX, HWND, (DLGPROC) About; ??? Break; ???? 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;
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) {? GLCLOR (GL_COLOR_BUFFER_BIT | GLBEGIN (GL_QUADS); ?? // Setting the drawing mode, we draw a flat four-sided shape? Glvertex2i (5, 5);? Glvertex2i (-5, 5) Glvertex2i (-5, -5); glvertex2i (5, -5) ;? glend (); SwapBuffers (g_hdc); ?? // exchange front and rear buffer, double buffer no flash} Void setModalMatrix (void) { ? Glmatrixmode (GL_MODELVIEW) ;? glloadIndentity ();? 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 OnIdle (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.
? 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, 0, ??? -5 ,? 5, 10,}
When drawing, we can draw a triangular painting in a triangle, or like the previous example, a quad-shaped four-sided painting, but in order to later we want some stuff, look at the triangular painting. 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, 6, 2, 4, 0, 6, 7 ,? 0, 7, 1, 3, 3, 2 ,? 0, 1, 3 ,? 5, 2, 3 ,? 5 , 4, 2, 9 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 point, with the right hand is in line with this triangle, the direction of the yaw 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 there are all things that I only owe Dongfeng, how do you 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 OnDraw's Clear and SWAP:
? // 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, let's 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 function, there is nothing to say Template
HRESULT ReduceTounit (Type * PVector)
{
? Double DLENGTH = SQRT (Double) PVector [0] * (double) PVector [0]
?? (double) PVector [1] * (double) PVector [1]
?? (double) PVector [2] * (double) PVector [2]);
? IF (Floatequal (DLENGTH, 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
HRESULT CALCNORMAL (Const T1 * PVertical, T2 * PNORMAL) {
? T1 D1 [3], D2 [3];
? D1 [0] = pVertical [0] - PVertical [3];
? D1 [1] = pVertical [1] - pVertical [4];
? D1 [2] = pVertical [2] - pVertical [5];
? d2 [0] = pVertical [3] - pVertical [6];
? D2 [1] = PVertical [4] - PVertical [7];
? D2 [2] = PVertical [5] - PVertical [8];
PNORMAL [0] = (T2) (D1 [1] * D2 [2] - D1 [2] * D2 [1]);
PNORMAL [1] = (T2) (D1 [2] * D2 [0] - D1 [0] * D2 [2]);
PNORMAL [2] = (T2) (D1 [0] * D2 [1] - D1 [1] * D2 [0]);
? Return ReduceTounit (PNORMAL);
}
The problem has appeared again, and a vertex can belong to different faces, but the normal vector is only one, and the normal vector of the vertex will cause the normal display of any side, so what should we do? Hardayly, "disassemble" with the index.
For (INT i = 0; i <36; i ) {? // ntempbox is a temporary array variable for saving the detached data. ? MoveMemory (& NTEMPBOX [i * 3], & nsrcbox [byindex [i] * 3], sizeof (ntempbox [0]) * 3);
??? Let's calculate the normal vector below.
For (int i = 0; i <12; i ) {? // calculate the triangle method of the triangle with the three vertices of a triangle? CalcNormal (& NTEMPBOX [i * 9], & fnormal [i * 9]); ? // and put this method 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 Method Vector GlnormalPointer (GL_FLOAT, 0, FNORMAL); ?? // Fill in the method vector array address
??? Because you don't need the index number, 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, 10, 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 class name
Template
HRESULT ReduceTounit (Type * PVector)
{
? Double DLENGTH = SQRT (Double) PVector [0] * (double) PVector [0]
?? (double) PVector [1] * (double) PVector [1]
?? (double) PVector [2] * (double) PVector [2]);
? IF (Floatequal (DLENGTH, 0.0, 1E-8))? {?? DLENGTH = 1.0;?}? pVector [0] / = (TYPE) DLENGTH;? PVector [1] / = (TYPE) DLENGTH;? PVector [2] / = (TYPE) DLENGTH;? RETURN S_OK;}
Template
HRESULT CALCNORMAL (Const T1 * Pvertical, T2 * PNORMAL)
{
? T1 D1 [3], D2 [3];
? D1 [0] = pVertical [0] - PVertical [3];
? D1 [1] = pVertical [1] - pVertical [4];
? D1 [2] = pVertical [2] - pVertical [5];
? d2 [0] = pVertical [3] - pVertical [6];
? D2 [1] = PVertical [4] - PVertical [7];
? D2 [2] = PVertical [5] - PVertical [8];
PNORMAL [0] = (T2) (D1 [1] * D2 [2] - D1 [2] * D2 [1]);
PNORMAL [1] = (T2) (D1 [2] * D2 [0] - D1 [0] * D2 [2]);
PNORMAL [2] = (T2) (D1 [0] * D2 [1] - D1 [1] * D2 [0]);
? Return ReduceTounit (PNORMAL);
}
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, ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? Lptstr ??? lpcmdline, ???????????????????? INT ?????? ncmdshow) {?? // Todo: Place the code here. ? 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 = loadAccelerators (Hinstance, (LPCTSTR) IDC_GLTEST);
? // Principal message loop:? While (TRUE)? {?? IF (PEEKMESG, NULL, 0, 0, PM_REMOVE)) ?? {??? if (! TranslateAccelerator (msg.hwnd, HaccelTable, & MSG) ) ??? {???? translateMessage (& msg); ???? DispatchMessage (& msg); ???} ??? continue; ??} ?? 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? = (wcex.cbclsextra ?? = 0; wcex.cbwndextra ?? = 0; wcex.hinstance ?? = hinstance;? wcex .hicon ??? = loadicon (Hinstance, (LPCTSTSTR) IDI_GLTEST);? wcex.hcursor ?? = loadcursor (null, idc_arrow) ;? wcex.hbrbackground? = (Hbrush) (color_window 1);? wcex.lpsz GenenaME? = (LPCTSTSTR) 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 the main window //// ?? Note: //// ??????? here In the 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) / / / /? Purpose: Handle the message of the main window. ////? WM_COMMAND? - Handling the application menu //? WM_PAINT? - Draw the main window //? WM_DESTROY? - Send an exit message and return to /// 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) About); ??? 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
?? IF (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);? 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 )? {?? cagcnormal (& 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_COLOR_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 (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 OnIdle (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
?