www.pudn.com > DialogOpenGL.rar > OpenGL.cpp
// OpenGL.cpp : implementation file // #include "stdafx.h" #include "DialogOpenGL.h" #include "OpenGL.h" #include#include #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif GLuint texureId; ///////////////////////////////////////////////////////////////////////////// // COpenGL COpenGL::COpenGL():m_bInit(FALSE),m_bFullScreen(FALSE), m_hDC(NULL),m_hRC(NULL),m_parent(NULL) { doRotate = false; mouseDown = false; firstSpot = secondSpot = false; dx = 0.0f, dy = 0.0f, dz = -5.0f; deep = 0.9f; } COpenGL::~COpenGL() { KillGLWindow(); // Shutdown } BEGIN_MESSAGE_MAP(COpenGL, CWnd) //{{AFX_MSG_MAP(COpenGL) ON_WM_CREATE() ON_WM_PAINT() ON_WM_SIZE() ON_WM_RBUTTONDOWN() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // COpenGL message handlers void COpenGL::Create(CRect rect, CWnd *parent) { if (m_bInit) return; ASSERT(rect); ASSERT(parent); m_rect = rect; m_parent = parent; CString className = AfxRegisterWndClass( CS_HREDRAW | CS_VREDRAW | CS_OWNDC, NULL, (HBRUSH)GetStockObject(BLACK_BRUSH), NULL); CreateEx( 0, className, "OpenGL", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, rect, parent, 0); } void COpenGL::Load3dsModel(CString filePath) { model.Load(filePath.GetBuffer(filePath.GetLength())); } void COpenGL::LoadTexture(CString filePath) { char strMessage[128] = {0}; model.addTexture = true; // 对有纹理的材质载入该纹理 if (!BuildTexture(filePath.GetBuffer(filePath.GetLength()), texureId)) { // 纹理载入失败 model.addTexture = false; sprintf(strMessage, "3DS纹理文件载入失败: %s !", filePath); MessageBox(strMessage, "Error", MB_OK); } } int COpenGL::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; // TODO: Add your specialized creation code here EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &m_DMsaved); GLuint PixelFormat; // Holds The Results After Searching For A Match static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format Must Support Window PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, // Must Support Double Buffering PFD_TYPE_RGBA, // Request An RGBA Format m_DMsaved.dmBitsPerPel, // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored 0, // No Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored 16, // 16Bit Z-Buffer (Depth Buffer) 0, // No Stencil Buffer 0, // No Auxiliary Buffer PFD_MAIN_PLANE, // Main Drawing Layer 0, // Reserved 0, 0, 0 // Layer Masks Ignored }; if ( !( m_hDC = ::GetDC ( m_hWnd ) ) ) { // Did We Get A Device Context? KillGLWindow (); // Reset The Display TRACE ( "Can't Create A GL Device Context." ); return FALSE; } if ( !( PixelFormat = ChoosePixelFormat ( m_hDC, &pfd ) ) ) { // Did Windows Find A Matching Pixel Format? KillGLWindow (); // Reset The Display TRACE ( "Can't Find A Suitable PixelFormat." ); return FALSE; } if ( !SetPixelFormat ( m_hDC, PixelFormat, &pfd ) ){ // Are We Able To Set The Pixel Format? KillGLWindow (); // Reset The Display TRACE ( "Can't Set The PixelFormat." ); return FALSE; } if ( !( m_hRC = wglCreateContext ( m_hDC ) ) ) { // Are We Able To Get A Rendering Context? KillGLWindow (); // Reset The Display TRACE( " Can't Create A GL Rendering Context." ); return FALSE; } if ( !wglMakeCurrent ( m_hDC, m_hRC ) ) { // Try To Activate The Rendering Context KillGLWindow (); // Reset The Display TRACE ( "Can't Activate The GL Rendering Context." ); return FALSE; } if ( !InitGL () ) { // Initialize Our Newly Created GL Window KillGLWindow (); // Reset The Display TRACE ( "Initialization Failed." ); return FALSE; } m_bInit = TRUE; return 0; } void COpenGL::KillGLWindow() { if (m_bFullScreen) // Are We In Fullscreen Mode? { if (!ChangeDisplaySettings(NULL,CDS_TEST)) { // if the shortcut doesn't work ChangeDisplaySettings(NULL,CDS_RESET); // Do it anyway (to get the values out of the registry) ChangeDisplaySettings(&m_DMsaved,CDS_RESET); // change it to the saved settings } else { ChangeDisplaySettings(NULL,CDS_RESET); } ShowCursor(TRUE); // Show Mouse Pointer } if ( m_hRC ) { // Do We Have A Rendering Context? if ( !wglMakeCurrent ( NULL, NULL ) ) { // Are We Able To Release The DC And RC Contexts? TRACE ( "Release Of DC And RC Failed." ); } if ( !wglDeleteContext ( m_hRC ) ) { // Are We Able To Delete The RC? TRACE ( "Release Rendering Context Failed." ); } m_hRC = NULL; // Set RC To NULL } if ( m_hDC && !::ReleaseDC ( m_hWnd, m_hDC ) ) { // Are We Able To Release The DC TRACE ( "Release Device Context Failed." ); m_hDC = NULL; // Set DC To NULL } if ( m_hWnd && !::DestroyWindow ( m_hWnd ) ) { // Are We Able To Destroy The Window? TRACE( "Could Not Release m_hWnd." ); m_hWnd = NULL; // Set m_hWnd To NULL } } int COpenGL::InitGL() { glShadeModel(GL_SMOOTH); // Enable Smooth Shading glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background glClearDepth(1.0f); // Depth Buffer Setup glEnable(GL_DEPTH_TEST); // Enables Depth Testing glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations glEnable(GL_TEXTURE_2D); // Enable Texture Mapping return TRUE; // Initialization Went OK } void COpenGL::RenderGLScene() { if(!m_bInit) return; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer glLoadIdentity(); // EXAMPLE OPENGL CODE START //////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// static GLfloat yrot; // Y Rotation glPushMatrix(); // Push Matrix Onto Stack (Copy The Current Matrix) glLoadIdentity(); // Reset The Current Modelview Matrix glTranslatef(dx, dy, dz); // Move Left 1.5 Units And Into The Screen 6.0 glRotatef(yrot,0.0f,1.0f,0.0f); // 从窗口坐标到OpenGL坐标的转换 double wx, wy, wz; if(mouseDown){ CString strZ, strW; this->GetParent()->GetDlgItemText(IDC_Z, strZ); this->GetParent()->GetDlgItemText(IDC_W, strW); deep = (float)atof(strZ.GetBuffer(strZ.GetLength ())); model.width = (float)atof(strW.GetBuffer(strW.GetLength ())); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); GLdouble mvmatrix[16], projmatrix[16]; glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); GLint realy = viewport[3] - mouse_y; gluUnProject((GLdouble)mouse_x, (GLdouble)realy, deep, mvmatrix, projmatrix, viewport, &wx, &wy, &wz); if(!firstSpot){ model.SetFirstTextureSpot((float)wx, (float)wy, (float)wz); firstSpot = true; secondSpot = false; } else if(!secondSpot){ model.SetSecondTextureSpot((float)wx, (float)wy, (float)wz); secondSpot = true; firstSpot = false; } mouseDown = false; } model.Render(); glPopMatrix(); // Pop Matrix Off The Stack if(doRotate) yrot+=1.2f; // Decrease The Rotation Variable For The Quad ////////////////////////////////////////////////////////////////////////////// // EXAMPLE OPENGL CODE END ////////////////////////////////////////////////////////// // Swap our scene to the front SwapBuffers(m_hDC); Invalidate(FALSE); } void COpenGL::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: Add your message handler code here ::ValidateRect ( m_hWnd, NULL ); // Do not call CWnd::OnPaint() for painting messages } void COpenGL::OnSize(UINT nType, int cx, int cy) { CWnd::OnSize(nType, cx, cy); // TODO: Add your message handler code here if ( cy==0) { // Prevent A Divide By Zero By cy=1; // Making Height Equal One } glViewport(0,0,cx,cy); // Reset The Current Viewport glMatrixMode(GL_PROJECTION); // Select The Projection Matrix glLoadIdentity(); // Reset The Projection Matrix gluPerspective(45.0f,(GLfloat)cx/(GLfloat)cy,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix glLoadIdentity(); // Reset The Modelview Matrix } void COpenGL::OnRButtonDown(UINT nFlags, CPoint point) { doRotate = !doRotate; CWnd::OnRButtonDown(nFlags, point); } void COpenGL::OnLButtonDown(UINT nFlags, CPoint point) { mouse_x = point.x; mouse_y = point.y; mouseDown = true; CWnd::OnLButtonDown(nFlags, point); } BOOL COpenGL::SetFullScreen(int width, int height, int depth) { if(!m_bInit) return FALSE; if (m_bFullScreen) return TRUE; DEVMODE dmScreenSettings; // Device Mode memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure dmScreenSettings.dmPelsWidth = width; // Selected Screen Width dmScreenSettings.dmPelsHeight = height; // Selected Screen Height dmScreenSettings.dmBitsPerPel = depth; // Selected Bits Per Pixel dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) { return m_bFullScreen = FALSE; } SetParent(NULL); SetWindowPos(&CWnd::wndTop, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW); ShowCursor(FALSE); SetFocus(); return m_bFullScreen = TRUE; } BOOL COpenGL::SetNormScreen() { if(!m_bInit) return FALSE; if (m_bFullScreen) // Are We In Fullscreen Mode? { if (!ChangeDisplaySettings(NULL,CDS_TEST)) { // if the shortcut doesn't work ChangeDisplaySettings(NULL,CDS_RESET); // Do it anyway (to get the values out of the registry) ChangeDisplaySettings(&m_DMsaved,CDS_RESET); // change it to the saved settings } else { ChangeDisplaySettings(NULL,CDS_RESET); } SetParent(m_parent); SetWindowPos(&CWnd::wndTop, m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), SWP_SHOWWINDOW); ShowCursor(TRUE); // Show Mouse Pointer m_bFullScreen = FALSE; } return TRUE; } // 构造函数 C3DSModel::C3DSModel() { g_ViewMode = GL_TRIANGLES; addTexture = false; spotNum = 0; width = 0.02f; // 初始化文件指针 m_FilePtr = NULL; // 定义一个默认的材质(灰色) tMaterial defaultMat; defaultMat.isTexMat = false; strcpy(defaultMat.matName.string, "5DG_Default"); defaultMat.color[0] = 192; defaultMat.color[1] = 192; defaultMat.color[2] = 192; m_3DModel.pMaterials.push_back(defaultMat); // 初始化保存3DS模型的结构体 m_3DModel.numOfMaterials = 1; m_3DModel.numOfObjects = 0; } // 析构函数 C3DSModel::~C3DSModel() { m_3DModel.pMaterials.clear(); m_3DModel.pObject.clear(); } // 载入3ds文件 BOOL C3DSModel::Load(char *strFileName) { char strMessage[128] = {0}; tChunk chunk = {0}; // 打开文件 m_FilePtr = fopen(strFileName,"rb"); // 如果文件打开失败 if (!m_FilePtr) { sprintf(strMessage, "3DS文件 %s 不存在!", strFileName); MessageBox(NULL, strMessage, "Error", MB_OK); return false; } // 读取3ds文件的第一个Chunk ReadChunk(&chunk); // 检查是否是3ds文件 if (chunk.ID != PRIMARY) { sprintf(strMessage, "读取文件 %s 失败!", strFileName); MessageBox(NULL, strMessage, "Error", MB_OK); fclose(m_FilePtr); return false; } // 开始读取3ds文件 ReadPrimary(chunk.length-6); // 计算每个顶点的法线量 ComputeNormals(); // 关闭打开的文件 fclose(m_FilePtr); m_FilePtr = NULL; return true; } // 从文件中读取1个字节 BYTE C3DSModel::ReadByte(void) { BYTE result = 0; fread(&result, 1, 1, m_FilePtr); return result; } // 从文件中读取2个字节 WORD C3DSModel::ReadWord(void) { return ReadByte() + (ReadByte()<<8); } // 从文件中读取4个字节 UINT C3DSModel::ReadUint(void) { return ReadWord() + (ReadWord()<<16); } // 从文件中读取浮点数 float C3DSModel::ReadFloat(void) { float result; fread(&result, sizeof(float), 1, m_FilePtr); return result; } // 从文件中读取字符串(返回字符串长度) UINT C3DSModel::ReadString(STRING *pStr) { int n=0; while ((pStr->string[n++]=ReadByte()) != 0) ; return n; } // 读取3ds的一个Chunk信息 void C3DSModel::ReadChunk(tChunk *pChunk) { fread(&pChunk->ID, 1, 2, m_FilePtr); fread(&pChunk->length, 1, 4, m_FilePtr); } // 读取3ds文件主要Chunk UINT C3DSModel::ReadPrimary(UINT n) { UINT count = 0; // 该Chunk内容已读取的字节计数 tChunk chunk = {0}; // 用以保存子Chunk的内容 while (count < n) { ReadChunk(&chunk); switch (chunk.ID) { case PRIM_EDIT: ReadEdit(chunk.length-6); break; default: fseek(m_FilePtr, chunk.length-6, SEEK_CUR); break; } count += chunk.length; } return count; } // 读取3ds物体主编辑Chunk UINT C3DSModel::ReadEdit(UINT n) { UINT count = 0; tChunk chunk = {0}; while(count < n) { ReadChunk(&chunk); switch(chunk.ID) { case EDIT_MAT: ReadMaterial(chunk.length-6); break; case EDIT_OBJECT: ReadObject(chunk.length-6); break; default: fseek(m_FilePtr, chunk.length-6, SEEK_CUR); break; } count += chunk.length; } return count; } // 读取3ds对象 UINT C3DSModel::ReadObject(UINT n) { UINT count = 0; tChunk chunk = {0}; // 新的3ds对象 t3DObject newObject = {0}; count += ReadString(&newObject.objName); m_3DModel.numOfObjects ++; while (count < n) { ReadChunk(&chunk); switch (chunk.ID) { case OBJECT_INFO: ReadObjectInfo(&newObject, n-count -6); break; default: fseek(m_FilePtr, chunk.length-6, SEEK_CUR); break; } count += chunk.length; } // 保存3ds对象 m_3DModel.pObject.push_back(newObject); return count; } // 读取3ds对象信息 UINT C3DSModel::ReadObjectInfo(t3DObject *pObj, UINT n) { UINT count = 0; tChunk chunk = {0}; while (count < n) { ReadChunk(&chunk); switch (chunk.ID) { case OBJECT_VERTEX: { pObj->numOfVerts = ReadWord(); pObj->pVerts = new Vector3[pObj->numOfVerts]; memset(pObj->pVerts, 0, sizeof(Vector3) * pObj->numOfVerts); // 按块读取顶点坐标值 fread(pObj->pVerts, 1, chunk.length - 8, m_FilePtr); // 调换y、z坐标值(由于3dMAX坐标系方向与OpenGL不同) float fTempY; for (int i = 0; i < pObj->numOfVerts; i++) { fTempY = pObj->pVerts[i].y; pObj->pVerts[i].y = pObj->pVerts[i].z; pObj->pVerts[i].z = -fTempY; } break; } case OBJECT_FACET: ReadFacetInfo(pObj,chunk.length-6); break; case OBJECT_UV: pObj->numTexVertex = ReadWord(); pObj->pTexVerts = new Vector2[pObj->numTexVertex]; memset(pObj->pTexVerts, 0, sizeof(Vector2) * pObj->numTexVertex); // 按块读取纹理坐标值 fread(pObj->pTexVerts, 1, chunk.length - 8, m_FilePtr); break; default: fseek(m_FilePtr, chunk.length-6, SEEK_CUR); break; } count += chunk.length; } return count; } // 读取面信息 UINT C3DSModel::ReadFacetInfo(t3DObject *pObj, UINT n) { UINT count = 0; tChunk chunk = {0}; pObj->numOfFaces = ReadWord(); pObj->pFaces = new tFace[pObj->numOfFaces]; memset(pObj->pFaces, 0, sizeof(tFace) * pObj->numOfFaces); // 读取面索引值(第4个值为3dMAX使用的参数,舍弃) for (int i=0; i numOfFaces; i++) { pObj->pFaces[i].vertIndex[0] = ReadWord(); pObj->pFaces[i].vertIndex[1] = ReadWord(); pObj->pFaces[i].vertIndex[2] = ReadWord(); ReadWord(); } count +=2+pObj->numOfFaces*8; STRING matName; int t; int matID = 0; while (count < n) { ReadChunk(&chunk); switch (chunk.ID) { case FACET_MAT: { ReadString(&matName); // 材质名称 t=ReadWord(); // 材质对应的面个数 // 查找对应的材质 for (int i=1;i<=m_3DModel.numOfMaterials;i++) { if (strcmp(matName.string, m_3DModel.pMaterials[i].matName.string) == 0) { matID = i; break; } } // 依据面索引给每个面绑定材质ID while (t>0) { pObj->pFaces[ReadWord()].matID = matID; t--; } break; } default: { fseek(m_FilePtr, chunk.length-6, SEEK_CUR); break; } } count += chunk.length; } return count; } // 读取材质 UINT C3DSModel::ReadMaterial(UINT n) { UINT count = 0; tChunk chunk = {0}; // 新的材质 tMaterial newMaterial = {0}; m_3DModel.numOfMaterials ++; while (count < n) { ReadChunk(&chunk); switch (chunk.ID) { case MAT_NAME: ReadString(&newMaterial.matName); break; case MAT_DIF: ReadMatDif (&newMaterial, chunk.length-6); break; case MAT_MAP: ReadMatMap(&newMaterial, chunk.length-6); break; default: fseek(m_FilePtr, chunk.length-6, SEEK_CUR); break; } count += chunk.length; } // 保存新的材质 m_3DModel.pMaterials.push_back(newMaterial); return count; } // 读取材质的漫反射属性 UINT C3DSModel::ReadMatDif (tMaterial *pMat, UINT n) { UINT count = 0; tChunk chunk = {0}; while (count color[0] = ReadByte(); pMat->color[1] = ReadByte(); pMat->color[2] = ReadByte(); break; default: fseek(m_FilePtr, chunk.length-6, SEEK_CUR); break; } count += chunk.length; } return count; } // 读取材质的纹理 UINT C3DSModel::ReadMatMap(tMaterial *pMat, UINT n) { UINT count = 0; tChunk chunk = {0}; while (count mapName); pMat->isTexMat = true; break; default: fseek(m_FilePtr, chunk.length-6, SEEK_CUR); break; } count += chunk.length; } return count; } // 绘制3ds模型 void C3DSModel::Render(void) { tMaterial *mat; t3DObject *obj; int *index; for (int nOfObj=0; nOfObj numOfFaces; nOfFace++) { index = obj->pFaces[nOfFace].vertIndex; mat = &m_3DModel.pMaterials[obj->pFaces[nOfFace].matID]; glEnable(GL_TEXTURE_2D); if(addTexture) glBindTexture(GL_TEXTURE_2D, texureId); // 选择该材质的纹理 glColor3ub(mat->color[0], mat->color[1], mat->color[2]); // 绘制三角形面 glBegin(g_ViewMode); glNormal3f(obj->pNormals[index[0]].x,obj->pNormals[index[0]].y,obj->pNormals[index[0]].z); glVertex3f(obj->pVerts[index[0]].x, obj->pVerts[index[0]].y, obj->pVerts[index[0]].z); glNormal3f(obj->pNormals[index[1]].x,obj->pNormals[index[1]].y,obj->pNormals[index[1]].z); glVertex3f(obj->pVerts[index[1]].x, obj->pVerts[index[1]].y, obj->pVerts[index[1]].z); glNormal3f(obj->pNormals[index[2]].x,obj->pNormals[index[2]].y,obj->pNormals[index[2]].z); glVertex3f(obj->pVerts[index[2]].x, obj->pVerts[index[2]].y, obj->pVerts[index[2]].z); glEnd(); glColor3f(1.0f, 1.0f, 1.0f); float cx1, cy1, cz1, cx2, cy2, cz2, lx1, ly1, lz1, lx2, ly2, lz2, rx3, ry3, rz3, rx4, ry4, rz4; bool horizon; for(int i = 0; i < spotNum;) { cx1 = textureSpots[i++]; cy1 = textureSpots[i++]; cz1 = textureSpots[i++]; cx2 = textureSpots[i++]; cy2 = textureSpots[i++]; cz2 = textureSpots[i++]; if(fabs(cx1-cx2)>fabs(cy1-cy2)){ lx1 = lx2 = cx1; rx3 = rx4 = cx2; ly1 = cy1 + width/2; ly2 = cy1 - width/2; ry3 = cy2 - width/2; ry4 = cy2 + width/2; lz1 = lz2 = cz1; rz3 = rz4 = cz2; horizon = true; } else{ ly1 = ry4 = cy1; ly2 = ry3 = cy2; lx1 = cx1 - width/2; lx2 = cx2 - width/2; rx3 = cx2 + width/2; rx4 = cx1 + width/2; lz1 = rz4 = cz1; lz2 = rz3 = cz2; horizon = false; } glBegin(GL_QUADS); if(addTexture) glTexCoord2f(0.05f, 0.05f); glVertex3f(lx1, ly1, lz1); if(addTexture) horizon? glTexCoord2f(0.0f, 0.95f) : glTexCoord2f(0.95f, 0.0f); glVertex3f(lx2, ly2, lz2); if(addTexture) glTexCoord2f(0.95f, 0.95f); glVertex3f(rx3, ry3, rz3); if(addTexture) horizon? glTexCoord2f(0.95f, 0.0f) : glTexCoord2f(0.0f, 0.95f); glVertex3f(rx4, ry4, rz4); glEnd(); } } } } // 释放3ds模型资源 void C3DSModel::Release(void) { m_3DModel.numOfMaterials = 1; while (m_3DModel.pMaterials.size() != 0) m_3DModel.pMaterials.pop_back(); m_3DModel.numOfObjects = 0; for (int nOfObj=0; nOfObj numOfFaces]; Vector3 *pTempNormals = new Vector3 [obj->numOfFaces]; obj->pNormals = new Vector3 [obj->numOfVerts]; for(int nOfFace=0; nOfFace numOfFaces; nOfFace++) { index = obj->pFaces[nOfFace].vertIndex; // 三角形的3个顶点 vPoly[0] = obj->pVerts[index[0]]; vPoly[1] = obj->pVerts[index[1]]; vPoly[2] = obj->pVerts[index[2]]; // 计算这个三角形的法线量 v1 = vPoly[0]-vPoly[1]; v2 = vPoly[2]-vPoly[1]; vNormal = Cross(v1, v2); pTempNormals[nOfFace] = vNormal; // 保存未单位化的法向量 vNormal = Normalize(vNormal); // 单位化法向量 pNormals[nOfFace] = vNormal; // 增加到法向量数组列表 } Vector3 vSum(0.0, 0.0, 0.0); Vector3 vZero(0.0, 0.0, 0.0); int shared=0; for (int nOfVert = 0; nOfVert < obj->numOfVerts; nOfVert++) // 遍历所有顶点 { for (int nOfFace = 0; nOfFace < obj->numOfFaces; nOfFace++) // 遍历包含该顶点的面 { if (obj->pFaces[nOfFace].vertIndex[0] == nOfVert || obj->pFaces[nOfFace].vertIndex[1] == nOfVert || obj->pFaces[nOfFace].vertIndex[2] == nOfVert) { vSum = vSum+pTempNormals[nOfFace]; shared++; } } obj->pNormals[nOfVert] = vSum/float(-shared); obj->pNormals[nOfVert] = Normalize(obj->pNormals[nOfVert]); vSum = vZero; shared = 0; } delete [] pTempNormals; delete [] pNormals; } } /////////////////////////////////////////////////////////////////////// //Load Texture #include // 标准输入输出头文件 #include // OLE控制库头文件 #include // 数学函数头文件 #include // OpenGL32库的头文件 BOOL BuildTexture(char *szPathName, GLuint &texid) // 载入图片并转换为纹理 { HDC hdcTemp; // DC用来保存位图 HBITMAP hbmpTemp; // 保存临时位图 IPicture *pPicture; // 定义IPicture Interface OLECHAR wszPath[MAX_PATH+1]; // 图片的完全路径 long lWidth; // 图像宽度 long lHeight; // 图像高度 long lWidthPixels; // 图像的宽带(以像素为单位) long lHeightPixels; // 图像的高带(以像素为单位) GLint glMaxTexDim ; // 保存纹理的最大尺寸 MultiByteToWideChar(CP_ACP, 0, szPathName, -1, wszPath, MAX_PATH); // 把ASCII码转化为Unicode标准码 HRESULT hr = OleLoadPicturePath(wszPath, 0, 0, 0, IID_IPicture, (void**)&pPicture); if(FAILED(hr)) // 如果导入失败 { // 图片载入失败出错信息 MessageBox (HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } hdcTemp = CreateCompatibleDC(GetDC(0)); // 建立窗口设备描述表 if(!hdcTemp) // 建立失败? { pPicture->Release(); // 释放IPicture // 图片载入失败出错信息 MessageBox (HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim); // 取得支持的纹理最大尺寸 pPicture->get_Width(&lWidth); // 取得IPicture 宽度 (转换为Pixels格式) lWidthPixels = MulDiv(lWidth, GetDeviceCaps(hdcTemp, LOGPIXELSX), 2540); pPicture->get_Height(&lHeight); // 取得IPicture 高度 (转换为Pixels格式) lHeightPixels = MulDiv(lHeight, GetDeviceCaps(hdcTemp, LOGPIXELSY), 2540); // 调整图片到最好的效果 if (lWidthPixels <= glMaxTexDim) // 图片宽度是否超过显卡最大支持尺寸 lWidthPixels = 1 << (int)floor((log((double)lWidthPixels)/log(2.0f)) + 0.5f); else // 否则,将图片宽度设为显卡最大支持尺寸 lWidthPixels = glMaxTexDim; if (lHeightPixels <= glMaxTexDim) // 图片高度是否超过显卡最大支持尺寸 lHeightPixels = 1 << (int)floor((log((double)lHeightPixels)/log(2.0f)) + 0.5f); else // 否则,将图片高度设为显卡最大支持尺寸 lHeightPixels = glMaxTexDim; // 建立一个临时位图 BITMAPINFO bi = {0}; // 位图的类型 DWORD *pBits = 0; // 指向位图Bits的指针 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // 设置结构大小 bi.bmiHeader.biBitCount = 32; // 32 位 bi.bmiHeader.biWidth = lWidthPixels; // 宽度像素值 bi.bmiHeader.biHeight = lHeightPixels; // 高度像素值 bi.bmiHeader.biCompression = BI_RGB; // RGB 格式 bi.bmiHeader.biPlanes = 1; // 一个位平面 // 建立一个位图这样我们可以指定颜色和深度 并访问每位的值 hbmpTemp = CreateDIBSection(hdcTemp, &bi, DIB_RGB_COLORS, (void**)&pBits, 0, 0); if(!hbmpTemp) // 建立失败? { DeleteDC(hdcTemp); // 删除设备描述表 pPicture->Release(); // 释放IPicture // 图片载入失败出错信息 MessageBox (HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } SelectObject(hdcTemp, hbmpTemp); // 选择临时DC句柄和临时位图对象 // 在位图上绘制IPicture pPicture->Render(hdcTemp, 0, 0, lWidthPixels, lHeightPixels, 0, lHeight, lWidth, -lHeight, 0); // 将BGR转换为RGB 将ALPHA值设为255 for(long i = 0; i < lWidthPixels * lHeightPixels; i++) // 循环遍历所有的像素 { BYTE* pPixel = (BYTE*)(&pBits[i]); // 获取当前像素 BYTE temp = pPixel[0]; // 临时存储第一个颜色像素(蓝色) pPixel[0] = pPixel[2]; // 将红色值存到第一位 pPixel[2] = temp; // 将蓝色值存到第三位 pPixel[3] = 255; // ALPHA值设为255 } glGenTextures(1, &texid); // 创建纹理 // 使用来自位图数据生成 的典型纹理 glBindTexture(GL_TEXTURE_2D, texid); // 绑定纹理 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 线形滤波 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 线形滤波 // 生成纹理 glTexImage2D(GL_TEXTURE_2D, 0, 3, lWidthPixels, lHeightPixels, 0, GL_RGBA, GL_UNSIGNED_BYTE, pBits); DeleteObject(hbmpTemp); // 删除对象 DeleteDC(hdcTemp); // 删除设备描述表 pPicture->Release(); // 释放 IPicture return TRUE; // 返回 TRUE }