全景图浏览器

让前面的程序成为一个全景图浏览器还要

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 (都很好)

}
效果图:




猜你喜欢

转载自blog.csdn.net/juebai123/article/details/79502190
今日推荐