让前面的程序成为一个全景图浏览器还要
1。一个命令行载入图
2。一个打开图像的对话框(右键菜单)
命令行加载:
init(); if(argc==2){ // 全路径读入一个纹理 PathBuildTexture(argv[1], SkyTexture[0]); m_sky.InitSky(0,0,0,R,SkyTexture[0]);//初始化天空球 }打开对话框:
void MenuProc(int id) { if(id==1){ string fn=myGetOpenFile(); printf("%s\n",fn.c_str()); char f[260]; strcpy(f, fn.c_str()); PathBuildTexture(f, SkyTexture[0]); m_sky.InitSky(0,0,0,R,SkyTexture[0]);//初始化天空球 } glutPostRedisplay(); }完整cpp:
//55 全景球浏览器 //左键(+ 移动)旋转,右键打开对话框,回车键(enter)全屏切换,按w、a、s、d、f、x、切换视角 #pragma comment( lib, "opengl32.lib" ) #pragma comment( lib, "glut32.lib") #include <GL/glut.h> #include <GL/glu.h> #include <math.h> #include <cstdlib> #include <string> #include <stdio.h> #include "ArcBall.h" #include "Sky.h" CSky m_sky; void setWidthHeight(GLint width ,GLint height); void screenshot(char* FileName); //全窗口 int BuildTexture(char *szPathName, GLuint &texid); // 全路径读入一个纹理 int PathBuildTexture(char *szPathName, GLuint &texid); //初始化,必须用全局变量的方式,不能用new ArcBallT arcBall(600.0f,400.0f); ArcBallT* ArcBall =&arcBall;// new ArcBallT(600.0f,400.0f);//&arcBall; #define PI 3.141592654 GLuint SkyTexture[10];//纹理 int width,height;//屏幕宽高 int R=100;//地图球半径 std::string direction;//方向 bool Shot=false; void reshape(int w, int h){ glViewport(0,0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); //GLdouble zNear=R*cos(PI/2); gluPerspective(90.0f, (GLfloat)w / (GLfloat)h, 6.5f, R*2);//zNear glMatrixMode(GL_MODELVIEW); ////ball ArcBall->setBounds((GLfloat)w, (GLfloat)h);//1. 设置窗口边界 } void init(){ glClearColor(0.0f, 0.0f, 0.0f, 0.5f); glClearDepth(1.0f); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); /* 启用纹理 */ glEnable(GL_TEXTURE_2D); /* 初始化天空 */ m_sky.InitSky(0,0,0,R,SkyTexture[0]);//初始化天空球 direction="前"; } void display (void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0,1.0,1.0); glLoadIdentity(); gluLookAt(0.0, 0.0, 0.0,//m_sky.GetSkyR()*ArcBall->zoomRate+5.0,//视点跟踪球大小 0.0, 0.0,R, 0.0, 1.0, 0.0); //glTranslatef(0,0,-3); glScalef(ArcBall->zoomRate, ArcBall->zoomRate, ArcBall->zoomRate);//2. 缩放 glScalef(-1.0, -1.0, -1.0);//2. 缩放 glMultMatrixf(ArcBall->Transform.M); //3. 旋转 //位置转到... if(direction=="后") glRotatef(180, 0.0, 1.0, 0.0); else if(direction=="左") glRotatef(90, 0.0, 1.0, 0.0); else if(direction=="右") glRotatef(-90, 0.0, 1.0, 0.0); else if(direction=="上") glRotatef(90, 1.0, 0.0, 0.0); else if(direction=="下") glRotatef(-90, 1.0, 0.0, 0.0); /* 绘制天空 */ m_sky.ShowSky() ; glFlush (); } //移动 void move(int x, int y) { ArcBall->MousePt.s.X = x; ArcBall->MousePt.s.Y = y; ArcBall->upstate(); glutPostRedisplay(); } //点击 void mouse(int button, int state, int x, int y) { if(button == GLUT_LEFT_BUTTON && state==GLUT_DOWN){ ArcBall->isClicked = true; move(x,y); } else if(button == GLUT_LEFT_BUTTON && state==GLUT_UP) ArcBall->isClicked = false; else if(button == GLUT_RIGHT_BUTTON && state==GLUT_DOWN){ ArcBall->isRClicked = true; move(x,y); } else if(button == GLUT_RIGHT_BUTTON && state == GLUT_UP) ArcBall->isRClicked = false; ArcBall->upstate(); glutPostRedisplay(); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; case '1': m_sky.T=SkyTexture[1]; break; case '2': m_sky.T=SkyTexture[2]; break; case '3': m_sky.T=SkyTexture[3]; break; case '4': m_sky.T=SkyTexture[4]; break; case '5': m_sky.T=SkyTexture[0]; break; case 13://按回车切换全屏 { static bool full=false; if (full) { glutReshapeWindow(width,height);//窗口 full=false; } else { glutFullScreen();//全屏 full=true; } } break; case 'w': { direction="上"; glutPostRedisplay(); Shot=true; } break; case 'f': { direction="后"; glutPostRedisplay(); Shot=true; } break; case 'x': { direction="下"; glutPostRedisplay(); Shot=true; } break; case 'a': { direction="左"; glutPostRedisplay(); Shot=true; } break; case 'd': { direction="右"; glutPostRedisplay(); Shot=true; } break; case 's'://前 { direction="前"; glutPostRedisplay(); Shot=true; } break; } glutPostRedisplay(); } //VC++:打开、保存文件对话框和浏览文件夹对话框 //2。API实现 string myGetOpenFile() { OPENFILENAMEA ofn; char szFile[260]; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = NULL; ofn.lpstrFile = szFile; ofn.lpstrFile[0] = '\0'; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = "全景图 (*.bmp,*.jpg)\0*.bmp;*.jpg;\0\0"; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = 0; string f; if (GetOpenFileNameA(&ofn)!=FALSE) f=ofn.lpstrFile; return f; } void MenuProc(int id) { if(id==1){ string fn=myGetOpenFile(); printf("%s\n",fn.c_str()); char f[260]; strcpy(f, fn.c_str()); PathBuildTexture(f, SkyTexture[0]); m_sky.InitSky(0,0,0,R,SkyTexture[0]);//初始化天空球 } glutPostRedisplay(); } int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); width=800;height=640; R=width/(2*sin(45*PI/180)); glutInitWindowSize(width,height); glutCreateWindow("全景浏览器"); init(); if(argc==2){ // 全路径读入一个纹理 PathBuildTexture(argv[1], SkyTexture[0]); m_sky.InitSky(0,0,0,R,SkyTexture[0]);//初始化天空球 } glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); //注册鼠标事件。 glutMotionFunc(move); //注册移动事件 glutKeyboardFunc(keyboard); glutCreateMenu(MenuProc); //菜单 glutAddMenuEntry("打开全景图",1); glutAttachMenu(GLUT_RIGHT_BUTTON);//关连到右键 glutMainLoop(); return 0; }全路径加载图函数(我是放在别的文件中的):
// 全路径读入一个纹理 int PathBuildTexture(char *szPathName, GLuint &texid) { HDC hdcTemp; // 用于保存位图的 DC HBITMAP hbmpTemp; // 暂时保存位图 IPicture *pPicture; // 图接口 OLECHAR wszPath[MAX_PATH+1]; // 图片的完整路径 (WCHAR) //char szPath[MAX_PATH+1]; // 图片的完整路径 long lWidth; // 逻辑单元宽度 long lHeight; // 逻辑单元高度 long lWidthPixels; // 以像素为单位的宽度 long lHeightPixels; // 以像素为单位的高度 GLint glMaxTexDim ; // 保持最大纹理大小 //printf("图片路径:%s\n",szPath); 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)) { // 如果加载失败 printf("装入纹理出错,可能是文件 %s 不存在!\n",szPathName); return FALSE; // 返回假 } hdcTemp = CreateCompatibleDC(GetDC(0)); // 创建与Windows兼容的设备上下文 if(!hdcTemp) // 创造失败了吗? { pPicture->Release(); // 递减图片参考计数 return FALSE; //返回假(失败) } glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim); // 获取支持的最大纹理大小 pPicture->get_Width(&lWidth); // 获取图宽度(转换为像素) lWidthPixels = MulDiv(lWidth, GetDeviceCaps(hdcTemp, LOGPIXELSX), 2540); pPicture->get_Height(&lHeight); // 获取图高度(转换为像素) lHeightPixels = MulDiv(lHeight, GetDeviceCaps(hdcTemp, LOGPIXELSY), 2540); // 将图像调整为最接近的2次方 if (lWidthPixels <= glMaxTexDim) // 图像宽度是否小于或等于卡限制 lWidthPixels = 1 << (int)floor((log((double)lWidthPixels)/log(2.0f)) + 0.5f); else // 否则设置宽度为 "最大功率的两个" 卡可以处理 lWidthPixels = glMaxTexDim; if (lHeightPixels <= glMaxTexDim) // Is Image Height Greater Than Cards Limit lHeightPixels = 1 << (int)floor((log((double)lHeightPixels)/log(2.0f)) + 0.5f); else // Otherwise Set Height To "Max Power Of Two" That The Card Can Handle lHeightPixels = glMaxTexDim; // 创建临时位图 BITMAPINFO bi = {0}; // 我们要的位图类型 DWORD *pBits = 0; // 指向位图位的指针 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // 设定结构尺寸 bi.bmiHeader.biBitCount = 32; // 32 位 bi.bmiHeader.biWidth = lWidthPixels; // Power Of Two Width bi.bmiHeader.biHeight = lHeightPixels; // 使图像向上(正Y轴) bi.bmiHeader.biCompression = BI_RGB; // RGB 编码 bi.bmiHeader.biPlanes = 1; // 1 Bitplane // 以这种方式创建位图允许我们指定颜色深度,并允许我们立即访问位 hbmpTemp = CreateDIBSection(hdcTemp, &bi, DIB_RGB_COLORS, (void**)&pBits, 0, 0); if(!hbmpTemp) // Did Creation Fail? { DeleteDC(hdcTemp); // 删除设备描述表(上下文) pPicture->Release(); // 递减图片参考计数 return FALSE; // Return False (Failure) } SelectObject(hdcTemp, hbmpTemp); // 选择处理我们的 temp DC 和我们的 temp 位图对象 // 将图片渲染到位图上 pPicture->Render(hdcTemp, 0, 0, lWidthPixels, lHeightPixels, 0, lHeight, lWidth, -lHeight, 0); // 将BGR转换为RGB格式,并添加255的α值 for(long i = 0; i < lWidthPixels * lHeightPixels; i++) // 循环通过所有像素 { BYTE* pPixel = (BYTE*)(&pBits[i]); // 获取当前像素 BYTE temp = pPixel[0]; // 将第一种颜色存储在 temp 变量(蓝色)中 pPixel[0] = pPixel[2]; // 将红色值移到正确位置(第一个) pPixel[2] = temp; // 将 temp 值移到正确的蓝色位置(第3个) // 这将使任何黑色像素完全透明(如果需要,可以硬编码该值) if ((pPixel[0]==0) && (pPixel[1]==0) && (pPixel[2]==0)) // 像素是完全黑色的吗? pPixel[3] = 0; // 将α值设置为0 else // Otherwise pPixel[3] = 255; // Set The Alpha Value To 255 } glGenTextures(1, &texid); // 创建纹理 // 使用位图中的数据生成典型纹理 glBindTexture(GL_TEXTURE_2D, texid); // 绑定到纹理id 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, GL_RGBA, lWidthPixels, lHeightPixels, 0, GL_RGBA, GL_UNSIGNED_BYTE, pBits); // (Modify This If You Want Mipmaps) DeleteObject(hbmpTemp); // Delete The Object DeleteDC(hdcTemp); // Delete The Device Context pPicture->Release(); // 递减图片参考计数 return TRUE; // Return True (都很好) }效果图: