位置: 编程技术 - 正文

OpenGL天空地形,场景漫游(opengl绘制地面)

编辑:rootadmin
&#;&#;

推荐整理分享OpenGL天空地形,场景漫游(opengl绘制地面),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:opengl星空,opengl星空,opengl绘制三维地形代码,opengl绘制地球,opengl绘制地面,opengl绘制地球,opengl绘制三维地形代码,opengl绘制地面,内容如对您有帮助,希望把文章链接给更多的朋友!

Camera.h camera.cppCBMPLoader.h CBMPLoader.cppFont.h Font.cppGLFrame.h GLFrame.cppGLWindow.h GLWindow.cppSkyAndTerrain.h SkyAndTerrain.cppSkyBox.h SkyBox.cppstdafx.h stdafx.cppTerrain.h Terrain.cppVector.h Vector.cpp

//========================================================/*** @file Camera.h** 项目描述: 构造天空和地面* 文件描述: 摄像机类 * 适用平台: Windows//NT/XP**/ //========================================================

#ifndef __CAMERA_H__#define __CAMERA_H__

#include "stdafx.h"#include "Vector.h" /**< 包含向量类头文件 */#include "GLFrame.h"

/** 摄像机类 */class Camera{public: /** 构造函数和析构函数 */ Camera(); ~Camera(); /** 获得摄像机状态方法 */ Vector3 getPosition() { return m_Position; } Vector3 getView() { return m_View; } Vector3 getUpVector() { return m_UpVector; } float getSpeed() { return m_Speed; }

/** 设置速度 */ void setSpeed(float speed) { m_Speed = speed; } /** 设置摄像机的位置, 观察点和向上向量 */ void setCamera(float positionX, float positionY, float positionZ, float viewX, float viewY, float viewZ, float upVectorX, float upVectorY, float upVectorZ);

/** 旋转摄像机方向 */ void rotateView(float angle, float X, float Y, float Z);

/** 根据鼠标设置摄像机观察方向 */ void setViewByMouse(); /** 左右摄像机移动 */ void yawCamera(float speed);

/** 前后移动摄像机 */ void moveCamera(float speed); /** 放置摄像机 */ void setLook();

//得到摄像机指针 static Camera* GetCamera(void) { return m_pCamera;}

private: /** 摄像机属性 */ static Camera *m_pCamera; /**< 当前全局摄像机指针 */ Vector3 m_Position; /**< 位置 */ Vector3 m_View; /**< 朝向 */ Vector3 m_UpVector; /**< 向上向量 */ float m_Speed; /**< 速度 */

};

#endif //__CAMERA_H__

//======================================================================/*** @file CBMPLoader.h** 项目描述: 构造天空和地面* 文件描述: 载入位图类 * 适用平台: Windows//NT/XP* */ //======================================================================

#ifndef __CBMPLOADER_H__#define __CBMPLOADER_H__

#include "stdafx.h"

#define BITMAP_ID 0x4D /**< 位图文件的标志 */

/** 位图载入类 */class CBMPLoader{ public: CBMPLoader(); ~CBMPLoader();

bool LoadBitmap(const char *filename); /**< 装载一个bmp文件 */ void FreeImage(); /**< 释放图像数据 */

unsigned int ID; /**< 生成纹理的ID号 */ int imageWidth; /**< 图像宽度 */ int imageHeight; /**< 图像高度 */ unsigned char *image; /**< 指向图像数据的指针 */};

#endif //__CBMPLOADER_H__

//========================================================/*** @file Font.h** 项目描述: 构造天空和地面* 文件描述: 字体类 * 适用平台: Windows//NT/XP*/ //========================================================#ifndef __GLFONT_H__#define __GLFONT_H__

#include "stdafx.h"

/** 定义字体类 */class GLFont {public: /** 构造函数和析构函数 */ GLFont(); ~GLFont(); ///成员方法 bool InitFont(); /**< 初始化字体 */ void PrintText(char *string, float x, float y); /**< 在(x,y)处输出string内容 */ protected: HFONT m_hFont; /**< 字体句柄 */ };

#endif // __GLFONT_H__

//======================================================================/*** @file GLFrame.h** 项目描述: 构造天空和地面* 文件描述: 键盘类和程序框架类 * 适用平台: Windows//NT/XP* * 你必须在你的继承类中完成以下函数的实现* * GLApplication * GLApplication::Create(const char * class_name) * 创建你的子类的一个实例 * * bool Init(); * 执行所有的初始化工作,如果成功函数返回true * * void Uninit(); * 执行所有的卸载工作 * * void Update(DWORD milliseconds); * 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位* * void Draw(); * 执行所有的绘制操作*/ //======================================================================#ifndef __GLFRAME_H__#define __GLFRAME_H__

#include "GLWindow.h" /**< 包含GLWindow.h头文件 */

/** 定义键盘类 */class Keys {public: /** 构造函数 */ Keys() { Clear(); } /** 清空所有的按键信息 */ void Clear() { ZeroMemory(&m_KeyDown, sizeof(m_KeyDown)); } /** 判断某个键是否按下 */ bool IsPressed(unsigned int key) { return (key < MAX_KEYS) ? (m_KeyDown[key] == true) : false; } /** 设置某个键被按下 */ void SetPressed(unsigned int key) { if (key < MAX_KEYS) m_KeyDown[key] = true; } /** 设置某个键被释放 */ void SetReleased(unsigned int key) { if (key < MAX_KEYS) m_KeyDown[key] = false; }

private: static const unsigned int MAX_KEYS = ; bool m_KeyDown[MAX_KEYS]; /**< 保存个按键的状态 */};

/** 基本的程序类,继承它用来创建OpenGL程序 */class GLApplication {public: /** 创建一个全局的Create函数,这个函数必须被继承类实现 */ static GLApplication * Create(const char * class_name); /**< 创建你自己的子类 */

/** 虚析构函数 */ virtual ~GLApplication() {};

protected: /** 下面的函数必须被继承类实现,完成基本的OpenGL渲染过程 */ virtual bool Init() = 0; /**< OpenGL的初始化 */ virtual void Uninit() = 0; /**< OpenGL的卸载 */ virtual void Update(DWORD milliseconds) = 0; /**< 执行OpenGL程序的更新 */ virtual void Draw() = 0; /**< 绘制OpenGL场景 */

/** 通用的函数 */ void ToggleFullscreen(); /**< 切换 全屏/窗口模式 */ void TerminateApplication(); /**< 结束程序 */ void ResizeDraw(bool enable) { m_ResizeDraw = enable; } /**< 设置在窗口改变大小的时候,可以绘制 */

Keys m_Keys; /**< 按键类 */ /** 构造函数 */ GLApplication(const char * class_name); private: /** 程序的主循环 */ friend int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); int Main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); /** 消息处理回调函数 */ friend LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT Message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

static const UINT WM_TOGGLEFULLSCREEN = (WM_USER &#; 1); /**< 自定义消息,在切换窗口模式的时候发送 */

GLWindow m_Window; /**< Window类 */ const char* m_ClassName; /**< 程序名 */ bool m_IsProgramLooping; /**< 程序循环标记,如果为false,则退出程序 */ bool m_CreateFullScreen; /**< 若为true,则创建全屏模式 */ bool m_IsVisible; /**< 窗口是否可见 */ bool m_ResizeDraw; /**< 是否在改变大小时,调用了绘制函数 */ DWORD m_LastTickCount; /**< 上一次计时器的&#; */};

#endif // __GLFRAMEWORK_H__

//========================================================/*** @file GLWindows.h** 项目描述: 构造天空和地面* 文件描述: 程序窗口类 * 适用平台: Windows//NT/XP*/ //========================================================#ifndef __GLWINDOW_H__#define __GLWINDOW_H__

#include "stdafx.h" /**< 包含stdafx.h头文件 */

/** windows窗口类 */class GLWindow {public: /** 构造函数 */ GLWindow(); /** 创建windows窗口 */ bool Create(const char * window_title, const char * class_name, bool fullscreen,HINSTANCE h_instance, LPVOID lpParam); /** 删除OpenGL窗口 */ void Destroy(); /** 改变窗口的显示设置 */ bool ChangeScreenSetting(); /** 当窗口大小改变时,通知OpenGL调整大小 */ void ReshapeGL(); /** Swap Buffers (Double Buffering) */ void SwapBuffers() { ::SwapBuffers(m_hDC); }

/** 设置窗口左上角的位置 */ void SetPosX(int x); void SetPosX(unsigned short x) { SetPosX((signed short)x); } void SetPosY(int y); void SetPosY(unsigned short y) { SetPosY((signed short)y); } /** 返回窗口的大小 */ int GetWidth(); int GetHeight(); /** 设置窗口的大小 */ void SetWidth(int width); void SetHeight(int height); /** 返回窗口左上角的位置 */ int GetPosX(); int GetPosY(); /** 设置窗口的颜色位深 */ void SetHiColor() { m_BitsPerPixel = ; } void SetTrueColor() { m_BitsPerPixel = ; }

/** 重载运算符,可以让GL_Window m_Window声明后的m_Window作为窗口句柄使用 */ operator HWND() { return m_hWnd; }

private: HWND m_hWnd; /**< 窗口句柄 */ HDC m_hDC; /**< 设备描述表 */ HGLRC m_hRC; /**< OpenGL渲染描述表 */

int m_WindowPosX; /**< 窗口的左上角的X位置 */ int m_WindowPosY; /**< 窗口的左上角的Y位置 */ int m_WindowWidth; /**< 窗口的宽度 */ int m_WindowHeight; /**< 窗口的高度 */ int m_ScreenWidth; /**< 全屏的宽度 */ int m_ScreenHeight; /**< 全屏的高度 */ int m_BitsPerPixel; /**< 颜色位深 */ bool m_IsFullScreen; /**< 是否全屏 */};

#endif // __GLWINDOW_H__

//=========================================================================/*** @file SkyAndTerrain.h** 项目描述: 构造天空和地面* 文件描述: 具体实例类 * 适用平台: Windows//NT/XP** 在这个类中您必须重载如下几个虚函数* * virtual bool Init(); * 执行所有的初始化工作,如果成功函数返回true * * virtual void Uninit(); * 执行所有的卸载工作 * * virtual void Update(DWORD milliseconds); * 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位* * virtual void Draw(); * 执行所有的绘制操作*///=========================================================================

#ifndef __SKY_AND_TERRAIN_H__#define __SKY_AND_TERRAIN_H__

#include "stdafx.h"#include "CBMPLoader.h"#include "GLFrame.h" /**< 包含基本的框架类 */#include "Font.h"#include "Camera.h"#include "SkyBox.h"#include "Terrain.h"

/** 从GL_Application派生出一个子类 */class SkyTerrain : GLApplication {public: bool Init(); /**< 执行所有的初始化工作,如果成功函数返回true */ void Uninit(); /**< 执行所有的卸载工作 */ void Update(DWORD milliseconds); /**< 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位 */ void Draw(); /**< 执行所有的绘制操作 */ void UpdateCamera(); /**< 更新摄像机 */ void CaculateFrameRate(); /**< 计算帧速 */ void PrintText(); /**< 输出文字信息 */ private: friend class GLApplication; /**< 父类为它的一个友元类,可以用来创建程序的实例,见函数GL_Application * GL_Application::Create(const char * class_name) */ SkyTerrain(const char * class_name); /**< 构造函数 */

/** 用户自定义的程序变量 */ CTerrain m_Terrain; /**< 地形类 */ CSkyBox m_SkyBox; /**< 天空类 */ GLFont m_Font; /**< 字体类 */ Camera m_Camera; /**< 摄像机类 */ float m_Fps; /**< 帧速 */ bool m_RenderMode; /**< 绘制模式 */ bool sp; /**< 空&#;键是否释放 */

};

#endif // __SKY_AND_TERRAIN_H__

//========================================================/*** @file SkyBox.h** 项目描述: 构造天空和地面* 文件描述: 天空盒类 * 适用平台: Windows//NT/XP* **/ //========================================================#ifndef __SKYBOX_H__#define __SKYBOX_H__

#include "stdafx.h"#include "CBMPLoader.h"#include "Vector.h"#include "Camera.h"

#define GL_CLAMP_TO_EDGE 0xF

/** 天空盒类 */class CSkyBox{public: /** 构造函数 */ CSkyBox(); ~CSkyBox();

/** 初始化 */ bool init(); /** 渲染 */ void render();

private: CBMPLoader m_texture[5]; /**< 天空盒纹理 */ Vector3 m_CameraPos; /**< 当前摄像机位置 */ float length; /**< 长度 */ float width; /**< 宽度 */ float height; /**< 高度 */ float yRot; /**< 绕Y轴旋转 */ };

#endif ///__SKYBOX_H__

/*=================================================== @file stdafx.h*/

#ifndef __STDAFX_H__#define __STDAFX_H__

/** 包含常用的头文件 */#include <windows.h>#include <stdio.h>#include <math.h> #include <time.h>

/** 包含gl头文件 */#include<GL/GLUT.H>#include <glaux.h>#include <glglext.h>

/** 包含OpenGL链接库文件 */#pragma comment(lib, "opengl.lib") #pragma comment(lib, "glu.lib") #pragma comment(lib, "glaux.lib")

/**< 禁止编译器出现类型转换的警告 */#pragma warning(disable: ) #pragma warning(disable: )#pragma warning(disable: )#pragma warning(disable: )#pragma warning(disable: )

/** 定义地面网&#; */const unsigned int MAP_WIDTH = ;const unsigned int CELL_WIDTH = ;

#endif

//========================================================/*** @file Terrain.h** 项目描述: 构造天空和地面* 文件描述: 地形类 * 适用平台: Windows//NT/XP* 修改日期: -- 加入了细节纹理,采用了多重纹理技术,使地表更富有细节感* -- 给地形加入了简单雾效 **/ //========================================================

#ifndef __TERRAIN_H__#define __TERRAIN_H__

#include "stdafx.h"#include "CBMPLoader.h"#include "camera.h"

/** 地形类 */class CTerrain{public: /** 构造函数 */ CTerrain();

~CTerrain();

/** 初始化地形 */ bool init();

/** 渲染地形 */ void render();

/** 设置是否使用细节纹理标志 */ void setDetail(bool _bDetail) { m_bDetail = _bDetail;} /** 获得地面高度 */ float getAveHeight(float x, float z); /** 得到当前Terrain指针 */ static CTerrain* GetTerrainPointer() { return m_pTerrain;}

private:

/** 设置地形的大小 */ void setSize(unsigned int width, unsigned int cell);

/** 载入'.raw'高度图 */ bool loadRawFile(const char* fileName);

/** 装载纹理 */ bool loadTexture();

/** 获得点(x,y)的高度信息 */ int getHeight(int x, int y);

/** 设置纹理坐标 */ void setTexCoord(float x, float z);

/** 设置雾效 */ void initFog();

public: static CTerrain* m_pTerrain; /**< 当前Terrain指针 */ unsigned int m_nWidth; /**< 地形网&#;数 */ unsigned int m_nCellWidth; /**< 每一&#;宽度 */ BYTE* m_pHeightMap; /**< 存放高度信息 */ CBMPLoader m_texture[2]; /**< 地面纹理和细节纹理 */ bool m_bDetail; /**< 是否使用细节纹理标志 */ int m_DetailScale; /**< 缩放比例 */ };

#endif //__TERRAIN_H__

//========================================================/*** @file Vector.h** 项目描述: 构造天空和地面* 文件描述: 向量类 * 适用平台: Windows//NT/XP**/ //========================================================

#ifndef __VECTOR_H__#define __VECTOR_H__

#include "stdafx.h"

/** 向量类 */class Vector3{public: /** 构造函数 */ Vector3() { x = 0.0; y = 0.0; z = 0.0; } Vector3( float xx, float yy, float zz) { x = xx; y = yy; z = zz; } Vector3(const Vector3& vec) { x = vec.x; y = vec.y; z = vec.z; } /** 成员函数 */ inline float length(); /**< 计算向量长度 */ Vector3 normalize(); /**< 单位化向量 */ float dotProduct(const Vector3& v); /**< 计算点积 */ Vector3 crossProduct(const Vector3& v); /**< 计算叉积 */

/** 重载操作符 */ Vector3 operator &#; (const Vector3& v); Vector3 operator - (const Vector3& v); Vector3 operator * (float scale); Vector3 operator / (float scale); Vector3 operator - (); public: float x,y,z;

};

#endif //__VECTOR_H__

//========================================================/*** @file Camera.cpp** 项目描述: 构造天空和地面* 文件描述: 摄像机类 * 适用平台: Windows//NT/XP**/ //========================================================

#include "stdafx.h"#include "Camera.h" /**< 包含摄像机头文件 */#include "Vector.h" /**< 包含向量类 */#include "GLFrame.h"

Camera* Camera::m_pCamera = NULL;

/** 构造函数 */Camera::Camera(){ /** 初始化向量&#; */ Vector3 zero = Vector3(0.0, 0.0, 0.0); Vector3 view = Vector3(0.0, 1.0, 0.5); Vector3 up = Vector3(0.0, 0.0, 1.0); /** 初始化摄像机 */ m_Position = zero; m_View = view; m_UpVector = up; m_Speed = 0.1f; m_pCamera = this;}

Camera::~Camera(){}

/** 设置摄像机的位置,朝向和向上向量 */void Camera::setCamera( float positionX, float positionY, float positionZ, float viewX, float viewY, float viewZ, float upVectorX, float upVectorY, float upVectorZ){ /** 构造向量 */ Vector3 Position = Vector3(positionX, positionY, positionZ); Vector3 View = Vector3(viewX, viewY, viewZ); Vector3 UpVector = Vector3(upVectorX, upVectorY, upVectorZ);

/** 设置摄像机 */ m_Position = Position; m_View = View; m_UpVector = UpVector; }

/** 旋转摄像机方向 */void Camera::rotateView(float angle, float x, float y, float z){ Vector3 newView;

/** 计算方向向量 */ Vector3 view = m_View - m_Position;

/** 计算 sin 和cos&#; */ float cosTheta = (float)cos(angle); float sinTheta = (float)sin(angle);

/** 计算旋转向量的x&#; */ newView.x = (cosTheta &#; (1 - cosTheta) * x * x) * view.x; newView.x &#;= ((1 - cosTheta) * x * y - z * sinTheta) * view.y; newView.x &#;= ((1 - cosTheta) * x * z &#; y * sinTheta) * view.z;

/** 计算旋转向量的y&#; */ newView.y = ((1 - cosTheta) * x * y &#; z * sinTheta) * view.x; newView.y &#;= (cosTheta &#; (1 - cosTheta) * y * y) * view.y; newView.y &#;= ((1 - cosTheta) * y * z - x * sinTheta) * view.z;

/** 计算旋转向量的z&#; */ newView.z = ((1 - cosTheta) * x * z - y * sinTheta) * view.x; newView.z &#;= ((1 - cosTheta) * y * z &#; x * sinTheta) * view.y; newView.z &#;= (cosTheta &#; (1 - cosTheta) * z * z) * view.z;

/** 更新摄像机的方向 */ m_View = m_Position &#; newView;}

/** 用鼠标旋转摄像机 */void Camera::setViewByMouse(){ POINT mousePos; /**< 保存当前鼠标位置 */ int middleX = GetSystemMetrics(SM_CXSCREEN) >> 1; /**< 得到屏幕宽度的一半 */ int middleY = GetSystemMetrics(SM_CYSCREEN) >> 1; /**< 得到屏幕高度的一半 */ float angleY = 0.0f; /**< 摄像机左右旋转角度 */ float angleZ = 0.0f; /**< 摄像机上下旋转角度 */ static float currentRotX = 0.0f; /** 得到当前鼠标位置 */ GetCursorPos(&mousePos); ShowCursor(TRUE); /** 如果鼠标没有移动,则不用更新 */ if( (mousePos.x == middleX) && (mousePos.y == middleY) ) return;

/** 设置鼠标位置在屏幕中心 */ SetCursorPos(middleX, middleY); /**< 得到鼠标移动方向 */ angleY = (float)( (middleX - mousePos.x) ) / .0f; angleZ = (float)( (middleY - mousePos.y) ) / .0f;

static float lastRotX = 0.0f; /**< 用于保存旋转角度 */ lastRotX = currentRotX; /** 跟踪摄像机上下旋转角度 */ currentRotX &#;= angleZ; /** 如果上下旋转弧度大于1.0,我们截取到1.0并旋转 */ if(currentRotX > 1.0f) { currentRotX = 1.0f; /** 根据保存的角度旋转方向 */ if(lastRotX != 1.0f) { /** 通过叉积找到与旋转方向垂直的向量 */ Vector3 vAxis = m_View - m_Position; vAxis = vAxis.crossProduct(m_UpVector); vAxis = vAxis.normalize(); ///旋转 rotateView( 1.0f - lastRotX, vAxis.x, vAxis.y, vAxis.z); } } /** 如果旋转弧度小于-1.0,则也截取到-1.0并旋转 */ else if(currentRotX < -1.0f) { currentRotX = -1.0f; if(lastRotX != -1.0f) { /** 通过叉积找到与旋转方向垂直的向量 */ Vector3 vAxis = m_View - m_Position; vAxis = vAxis.crossProduct(m_UpVector); vAxis = vAxis.normalize(); ///旋转 rotateView( -1.0f - lastRotX, vAxis.x, vAxis.y, vAxis.z); } } /** 否则就旋转angleZ度 */ else { /** 找到与旋转方向垂直向量 */ Vector3 vAxis = m_View - m_Position; vAxis = vAxis.crossProduct(m_UpVector); vAxis = vAxis.normalize(); ///旋转 rotateView(angleZ, vAxis.x, vAxis.y, vAxis.z); }

/** 总是左右旋转摄像机 */ rotateView(angleY, 0, 1, 0);}

/** 左右移动摄像机 */void Camera::yawCamera(float speed){ Vector3 yaw; Vector3 oldPos,oldView; Vector3 cross = m_View - m_Position; oldPos = m_Position; oldView = m_View; cross = cross.crossProduct(m_UpVector);

///归一化向量 yaw = cross.normalize(); m_Position.x &#;= yaw.x * speed; m_Position.z &#;= yaw.z * speed;

m_View.x &#;= yaw.x * speed; m_View.z &#;= yaw.z * speed; /** 进行边界检查和限定 */ if(m_View.x > MAP_WIDTH - || m_View.x < 2*CELL_WIDTH) { m_Position.x = oldPos.x ; m_View.x = oldView.x; }

if(m_View.z > MAP_WIDTH - || m_View.z < 2*CELL_WIDTH) { m_Position.z = oldPos.z ; m_View.z = oldView.z; }

}

/** 前后移动摄像机 */void Camera::moveCamera(float speed){ /** 计算方向向量 */ Vector3 vector = m_View - m_Position; vector = vector.normalize(); /**< 单位化 */ Vector3 oldPos,oldView; oldPos = m_Position; oldView = m_View; /** 更新摄像机 */ m_Position.x &#;= vector.x * speed; /**< 根据速度更新位置 */ m_Position.z &#;= vector.z * speed; m_Position.y &#;= vector.y * speed; m_View.x &#;= vector.x * speed; /**< 根据速度更新方向 */ m_View.y &#;= vector.y * speed; m_View.z &#;= vector.z * speed; /** 进行边界检查和限定 */ if(m_View.x > MAP_WIDTH - || m_View.x < 2*CELL_WIDTH) { m_Position.x = oldPos.x ; m_View.x = oldView.x; }

if(m_View.z > MAP_WIDTH - || m_View.z < 2*CELL_WIDTH) { m_Position.z = oldPos.z ; m_View.z = oldView.z; }

}

/** 设置视点 */void Camera::setLook(){ /** 设置视口 */ gluLookAt(m_Position.x, m_Position.y, m_Position.z, m_View.x, m_View.y, m_View.z, m_UpVector.x, m_UpVector.y, m_UpVector.z);}

//======================================================================/*** @file CBMPLoader.cpp** 项目描述: 构造天空和地面* 文件描述: 载入位图类 * 适用平台: Windows//NT/XP*/ //======================================================================

#include"CBMPLoader.h" /**< 包含头文件 */

/** 构造函数 */CBMPLoader::CBMPLoader(){ /** 初始化成员&#;为0 */ image = 0; imageWidth = 0; imageHeight = 0;}

/** 析构函数 */CBMPLoader::~CBMPLoader(){ FreeImage(); /**< 释放图像数据占据的内存 */}

/** 装载一个位图文件 */bool CBMPLoader::LoadBitmap(const char *file){ FILE *pFile = 0; /**< 文件指针 */ /** 创建位图文件信息和位图文件头结构 */ BITMAPINFOHEADER bitmapInfoHeader; BITMAPFILEHEADER header; unsigned char textureColors = 0;/**< 用于将图像颜色从BGR变换到RGB */

/** 打开文件,并检查错误 */ pFile = fopen(file, "rb"); if(pFile == 0) return false;

/** 读入位图文件头信息 */ fread(&header, sizeof(BITMAPFILEHEADER), 1, pFile); /** 检查该文件是否为位图文件 */ if(header.bfType != BITMAP_ID) { fclose(pFile); /**< 若不是位图文件,则关闭文件并返回 */ return false; }

/** 读入位图文件信息 */ fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, pFile);

/** 保存图像的宽度和高度 */ imageWidth = bitmapInfoHeader.biWidth; imageHeight = bitmapInfoHeader.biHeight;

/** 确保读取数据的大小 */ if(bitmapInfoHeader.biSizeImage == 0) bitmapInfoHeader.biSizeImage = bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * 3;

/** 将指针移到数据开始位置 */ fseek(pFile, header.bfOffBits, SEEK_SET);

/** 分配内存 */ image = new unsigned char[bitmapInfoHeader.biSizeImage];

/** 检查内存分配是否成功 */ if(!image) /**< 若分配内存失败则返回 */ { delete[] image; fclose(pFile); return false; }

/** 读取图像数据 */ fread(image, 1, bitmapInfoHeader.biSizeImage, pFile);

/** 将图像颜色数据&#;式进行交换,由BGR转换为RGB */ for(int index = 0; index < (int)bitmapInfoHeader.biSizeImage; index&#;=3) { textureColors = image[index]; image[index] = image[index &#; 2]; image[index &#; 2] = textureColors; } fclose(pFile); /**< 关闭文件 */ return true; /**< 成功返回 */}

/** 释放内存 */void CBMPLoader::FreeImage(){ /** 释放分配的内存 */ if(image) { delete[] image; image = 0; }}

/*** @file GLFont.cpp** 项目描述: 构造天空和地面* 文件描述: 字体类 * 适用平台: Windows//NT/XP**/ //========================================================

#include "Font.h"

GLFont::GLFont(){}/** 析构函数 */GLFont::~GLFont(){ if(m_hFont) DeleteObject(m_hFont); /**< 删除字体句柄 */}/** 初始化字体 */bool GLFont::InitFont(){ /**< 创建字体 */ m_hFont = CreateFont(-, /**< 字体高度 */ 0, /**< 字体宽度 */ 0, /**< 字体的旋转角度 Angle Of Escapement */ 0, /**< 字体底线的旋转角度Orientation Angle */ FW_BOLD, /**< 字体的重量 */ FALSE, /**< 是否使用斜体 */ FALSE, /**< 是否使用下划线 */ FALSE, /**< 是否使用删除线 */ GB_CHARSET, /**< 设置字符集 */ OUT_TT_PRECIS, /**< 输出精度 */ CLIP_DEFAULT_PRECIS, /**< 裁剪精度 */ ANTIALIASED_QUALITY, /**< 输出质量 */ FF_DONTCARE|DEFAULT_PITCH, /**< Family And Pitch */ "宋体"); /**< 字体名称 */ if(!m_hFont) return false; /**< 创建字体失败则返回 */ /** 初始化成功则返回true */ return true;}

/** 在指定位置输出字符串 */void GLFont::PrintText(char *string, float x, float y){ HBITMAP hBitmap,hOldBmp; /**< 定义两个位图句柄 */ BITMAP bm; /**< 位图结构变量 */ SIZE size; /**< 位图尺寸 */ GLboolean lp,tp; HDC hDC = ::CreateCompatibleDC(0); /**< 暂存设备场景 */ glGetBooleanv(GL_LIGHTING,&lp); /**< 查看场景中是否有光照 */ glGetBooleanv(GL_TEXTURE_2D,&tp);/**< 查看场景中是否启用纹理 */ /** 保存和设置一些属性 */ glLoadIdentity(); glPushMatrix(); glTranslatef(0,0,-.0f); glDisable(GL_LIGHTING); /**< 关闭光照 */ glDisable(GL_TEXTURE_2D); /**< 关闭纹理 */ glDisable(GL_DEPTH_TEST); /**< 关闭深度测试 */ SelectObject(hDC, m_hFont); /**< 选择字体 */ ::GetTextExtentPoint(hDC, string, strlen(string), &size);/**< 获取字符位图大小 */ hBitmap = CreateBitmap(size.cx, size.cy,1, 1, NULL); /**< 创建与hDC相关单色位图 */ hOldBmp = (HBITMAP)SelectObject(hDC,hBitmap); /**< 选择位图 */ SetBkColor(hDC, RGB(0, 0, 0)); /**< 背景色为黑色 */ SetTextColor(hDC, RGB(, , )); /**< 字体颜色白色 */ SetBkMode(hDC, OPAQUE); /**< 用当前的背景颜色填充背景 */ TextOut(hDC, 0, 0, string, strlen(string)); /**< 输出文字到暂存hDC */ /** 获得相关位图数据结构 */ GetObject(hBitmap, sizeof(bm), &bm); size.cx = (bm.bmWidth &#; ) & (~); /**< 边缘对齐 */ size.cy = bm.bmHeight; int bufsize = size.cx * size.cy/8; /**< 图形数据长度 */ /** 定义单色位图结构 */ struct { BITMAPINFOHEADER bih; RGBQUAD col[2]; }bic; /** 获取单色位图结构信息 */ BITMAPINFO *binf = (BITMAPINFO *)&bic; binf->bmiHeader.biSize = sizeof(binf->bmiHeader); /**< 修改结构信息 */ binf->bmiHeader.biWidth = bm.bmWidth; binf->bmiHeader.biHeight = bm.bmHeight; binf->bmiHeader.biPlanes = 1; binf->bmiHeader.biBitCount = 1; /**< 单色 */ binf->bmiHeader.biCompression = BI_RGB; /**< 颜色方式 */ binf->bmiHeader.biSizeImage = bufsize; binf->bmiHeader.biXPelsPerMeter = 1; binf->bmiHeader.biYPelsPerMeter = 1; binf->bmiHeader.biClrUsed = 0; binf->bmiHeader.biClrImportant = 0; /** 定义图形数据块 */ UCHAR* pBmpBits = new UCHAR[bufsize]; memset(pBmpBits, 0, sizeof(UCHAR)*bufsize); /** 将设备无关数据保存在pBmpBits指向的数据块中 */ ::GetDIBits(hDC, hBitmap, 0, bm.bmHeight, pBmpBits, binf,DIB_RGB_COLORS); /** 显示字符串 */ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /**< 指定像素存储模式 */ glRasterPos2f(x,y); /**< 定位 */ glBitmap(size.cx, size.cy, 0.0, 0.0, 0.0, 0.0, pBmpBits); /**< 位图显示 */ delete pBmpBits; /**< 删除指针 */ SelectObject(hDC, hOldBmp); /**< 恢复原来位图信息 */ DeleteObject(hBitmap); ::DeleteDC(hDC); /** 恢复一些属性 */ if(lp) glEnable(GL_LIGHTING); /**< 启用光照 */ if(tp) glEnable(GL_TEXTURE_2D); /**< 启用纹理 */ glEnable(GL_DEPTH_TEST); /**< 启用深度测试 */ glPopMatrix();}

//======================================================================/*** @file GLFrame.cpp** 项目描述: 构造天空和地面* 文件描述: 键盘类和程序框架类 * 适用平台: Windows//NT/XP* * * 你必须在你的继承类中完成以下函数的实现* * GLApplication * GLApplication::Create(const char * class_name) * 创建你的子类的一个实例 * * bool Init(); * 执行所有的初始化工作,如果成功函数返回true * * void Uninit(); * 执行所有的卸载工作 * * void Update(DWORD milliseconds); * 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位* * void Draw(); * 执行所有的绘制操作*/ //======================================================================

#include "stdafx.h"#include "GLFrame.h" /**< 包含GLFrame.h头文件 */

/** 主程序入口 */int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ int ret = -1; GLApplication * appl = GLApplication::Create("OpenGL"); /**< 创建程序类 */ if (appl != 0) { ret = appl->Main(hInstance, hPrevInstance, lpCmdLine, nCmdShow);/**< 执行程序主循环 */ delete appl; /**< 删除程序类(在继承类中,使用GL_Example * example = new GL_Example(class_name);分配了一块内存)*/ } else { /**< 创建程序出错 */ MessageBox(HWND_DESKTOP, "创建程序出错", "Error", MB_OK | MB_ICONEXCLAMATION); } return ret;}

/** 处理窗口消息 */LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ LONG user_data = GetWindowLong(hWnd, GWL_USERDATA); /**< 返回用户自定义的位的程序附加&#; */ if (user_data == 0) { /// 如果程序第一次运行 if (uMsg == WM_CREATE) /**< 处理窗口创建消息 */ { /// 返回窗口结构的指针,它保存刚创建的程序实例的类 CREATESTRUCT * creation = reinterpret_cast<CREATESTRUCT *>(lParam); /// 获得程序实例的指针 GLApplication * appl = reinterpret_cast<GLApplication *>(creation->lpCreateParams); /// 保存程序实例的指针为用户自定义的程序附加&#; SetWindowLong(hWnd, GWL_USERDATA, reinterpret_cast<LONG>(appl)); appl->m_IsVisible = true; /**< 设置程序可见 */ return 0; /**< 返回 */ } } else { /// 如果不是第一次窗口,返回程序实例的指针 GLApplication * appl = reinterpret_cast<GLApplication *>(user_data); return appl->Message(hWnd, uMsg, wParam, lParam); /**< 调用程序实例自己的消息处理函数 */ }

return DefWindowProc(hWnd, uMsg, wParam, lParam); /**< 调用默认的窗口消息处理函数 */}

/** 构造函数 */GLApplication::GLApplication(const char * class_name) { m_ClassName = class_name; /**< 保存类名 */ m_IsProgramLooping = true; /**< 设置程序循环为true */ m_CreateFullScreen = true; /**< 使用全屏模式 */ m_IsVisible = false; /**< 不可见 */ m_ResizeDraw = false; /**< 在窗口改变大小的时候,不可绘制 */ m_LastTickCount = 0;}

void GLApplication::ToggleFullscreen() /**< 切换 全屏/窗口模式 */{ PostMessage(m_Window, WM_TOGGLEFULLSCREEN, 0, 0); /**< 发送自定的切换消息 */}

void GLApplication::TerminateApplication() /**< 结束程序 */{ PostMessage(m_Window, WM_QUIT, 0, 0); /**< 发送退出消息 */ m_IsProgramLooping = false; /**< 停止程序循环 */}

/** 消息循环 */LRESULT GLApplication::Message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ switch (uMsg) /**< 处理不同的Windows消息 */ { case WM_SYSCOMMAND: /**< 截获系统命令 */ switch (wParam) { case SC_SCREENSAVE: /**< 截获屏幕保护启动命令 */ case SC_MONITORPOWER: /**< 截获显示其省电模式启动命令 */ return 0; /**< 不启用这两个命令 */ break; } break; /**< 退出 */

case WM_CLOSE: /**< 关闭窗口 */ TerminateApplication(); /**< 调用TerminateApplication函数 */ return 0; break;

case WM_EXITMENULOOP: case WM_EXITSIZEMOVE: m_LastTickCount = GetTickCount(); /**< 更新计数器的&#; */ return 0; break;

case WM_MOVE: m_Window.SetPosX(LOWORD(lParam)); /**< 更新鼠标的坐标 */ m_Window.SetPosY(HIWORD(lParam)); return 0; break;

case WM_PAINT: if (m_ResizeDraw == true) /**< 如果需要重绘 */ { m_Window.ReshapeGL(); /**< 重新设置窗口的大小 */ Draw(); /**< 重新绘制 */ m_Window.SwapBuffers(); /**< 交换前后帧缓存 */ } break;

case WM_SIZING: /**< 窗口正在改变大小 */ { RECT * rect = (RECT *)lParam; m_Window.SetWidth(rect->right - rect->left); /**< 设置窗口宽度 */ m_Window.SetHeight(rect->bottom - rect->top); /**< 设置窗口高度 */ return TRUE; } break;

case WM_SIZE: /**< 窗口改变大小后 */ switch (wParam) /**< 处理不同的窗口状态 */ { case SIZE_MINIMIZED: /**< 是否最小化? */ m_IsVisible = false; /**< 如果是,则设置不可见 */ return 0; break;

case SIZE_MAXIMIZED: /**< 窗口是否最大化? */ case SIZE_RESTORED: /**< 窗口被还原? */ m_IsVisible = true; /**< 设置为可见 */ m_Window.SetWidth(LOWORD(lParam)); /**< 设置窗口宽度 */ m_Window.SetHeight(HIWORD(lParam)); /**< 设置窗口高度 */ m_Window.ReshapeGL(); /**< 改变窗口大小 */ m_LastTickCount = GetTickCount(); /**< 更新计数器的&#; */ return 0; break; } break;

case WM_KEYDOWN: /**< 更新按键信息 */ m_Keys.SetPressed(wParam); return 0; break;

case WM_KEYUP: /**< 更新释放键信息 */ m_Keys.SetReleased(wParam); return 0; break;

case WM_TOGGLEFULLSCREEN: /**< 切换 全屏/窗口模式 */ m_CreateFullScreen = !m_CreateFullScreen; PostMessage(hWnd, WM_QUIT, 0, 0); break; }

return DefWindowProc(hWnd, uMsg, wParam, lParam); /**< 调用默认的窗口消息处理函数 */}

/** 程序的主循环 */int GLApplication::Main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ /// 注册一个窗口 WNDCLASSEX windowClass; /**< 窗口类 */ ZeroMemory(&windowClass, sizeof(WNDCLASSEX)); /**< 清空结构为0 */ windowClass.cbSize = sizeof(WNDCLASSEX); /**< 窗口结构的大小 */ windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; /**< 设置窗口类型为,移动时重画,并为窗口取得DC */ windowClass.lpfnWndProc = (WNDPROC)(WindowProc); /**< WndProc处理消息 */ windowClass.hInstance = hInstance; /**< 设置实例 */ windowClass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE); /**< 设置背景 */ windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); /**< 载入光标 */ windowClass.lpszClassName = m_ClassName; /**< 设置类名 */ if (RegisterClassEx(&windowClass) == 0) /**< 尝试注册窗口类 */ { /**< NOTE: Failure, Should Never Happen */ MessageBox(HWND_DESKTOP, "注册窗口失败!", "Error", MB_OK | MB_ICONEXCLAMATION); return -1; /**< 退出并返回FALSE */ }

OpenGL天空地形,场景漫游(opengl绘制地面)

// 询问是否在全屏状态下运行? if (MessageBox(HWND_DESKTOP, "你想在全屏状态下运行么 ?", "设置运行模式", MB_YESNO | MB_ICONQUESTION) == IDNO) { m_CreateFullScreen = false; /**< m_CreateFullScreen记录当前的显示模式为窗口 */ } while (m_IsProgramLooping) /**< 循环直到WM_QUIT退出程序 */ { /// 创建一个窗口 if (m_Window.Create("OpenGL 3D游戏编程——构造天空和地面", m_ClassName,m_CreateFullScreen, hInstance, this) == true) { /// 如果初始化失败,则退出 if (Init() == false) /**< 调用自定义的初始化函数 */ { /**< 失败 */ TerminateApplication(); /**< 关闭窗口退出程序 */ } else /**< 成功开始消息循环 */ { MSG msg; /**< Window消息结构 */ bool isMessagePumpActive = true; /**< 当消息不为空时,处理消息循环 */ m_LastTickCount = GetTickCount(); /**< 返回当前的计时器的&#; */ m_Keys.Clear(); /**< 清空所有的按键信息 */ while (isMessagePumpActive == true) /**< 当消息不为空时,处理消息循环 */ { /**< 成功创建窗口,检测窗口消息 */ if (PeekMessage(&msg, m_Window, 0, 0, PM_REMOVE) != 0) { /// 检测是否为WM_QUIT消息 if (msg.message != WM_QUIT) { DispatchMessage(&msg); /**< 如果不是发送消息到消息回调函数中处理 */ } else { isMessagePumpActive = false; /**< 如果是,则退出 */ } } /// 如果没有消息 else { if (m_IsVisible == false) /**< 如果窗口不可见 */ { WaitMessage(); /**< 暂停程序,等待消息 */ } else /**< 如果窗口可见 */ { /**< 执行消息循环 */ DWORD tickCount = GetTickCount(); /**< 返回计时器的当前&#; */ Update(tickCount - m_LastTickCount); /**< 调用用户自定义的更新函数 */ m_LastTickCount = tickCount; /**< 重新设置上一次,计数器的&#; */ Draw(); /**< 调用用户自定义的绘制函数 */ m_Window.SwapBuffers(); /**< 交换前后帧缓存 */ } } } /**< 如果isMessagePumpActive == true,则循环 */ } /**< 程序结束 */ Uninit(); /**< 用户自定义的卸载函数 */ m_Window.Destroy(); /**< 删除窗口 */ } else /**< 如果创建窗口失败 */ { MessageBox(HWND_DESKTOP, "创建OpenGL窗口错误", "Error", MB_OK | MB_ICONEXCLAMATION); m_IsProgramLooping = false; /**< 停止程序循环 */ } }

UnregisterClass(m_ClassName, hInstance); /**< 取消注册的窗口 */ return 0;}

//========================================================/*** @file GLWindows.h** 项目描述: 使用OO的OpenGL程序框架演示* 文件描述: 程序窗口类 * 适用平台: Windows//NT/XP* **/ //========================================================#include "GLWindow.h" /**< 包含GLwindows.h头文件 */

#include <gl/gl.h> /**< 包含OpenGL头文件 */#include <gl/glu.h>

/** 构造函数 */GLWindow::GLWindow() { m_WindowPosX = 0; /**< 窗口的左上角的X位置 */ m_WindowPosY = 0; /**< 窗口的左上角的Y位置 */ m_WindowWidth = ; /**< 窗口的宽度 */ m_WindowHeight = ; /**< 窗口的高度 */ m_ScreenWidth = ; /**< 全屏的宽度 */ m_ScreenHeight = ; /**< 全屏的高度 */ m_BitsPerPixel = ; /**< 颜色位深 */ m_IsFullScreen = false; /**< 不使用全屏 */

m_hWnd = 0; m_hDC = 0; m_hRC = 0;}

/** 返回窗口的大小 */int GLWindow::GetWidth(){ if (m_IsFullScreen == true) { return m_ScreenWidth; } else { return m_WindowWidth; }}int GLWindow::GetHeight(){ if (m_IsFullScreen == true) { return m_ScreenHeight; } else { return m_WindowHeight; }}

/** 设置窗口的大小 */void GLWindow::SetWidth(int width){ if (m_IsFullScreen == true) { m_ScreenWidth = width; } else { m_WindowWidth = width; }}void GLWindow::SetHeight(int height){ if (m_IsFullScreen == true) { m_ScreenHeight = height; } else { m_WindowHeight = height; }}

/** 返回窗口左上角的位置 */int GLWindow::GetPosX(){ if (m_IsFullScreen == false) { return m_WindowPosX; } return 0;}int GLWindow::GetPosY(){ if (m_IsFullScreen == false) { return m_WindowPosY; } return 0;}

/** 设置窗口左上角的位置 */void GLWindow::SetPosX(int x){ if (m_IsFullScreen == false) { m_WindowPosX = x; }}void GLWindow::SetPosY(int y){ if (m_IsFullScreen == false) { m_WindowPosY = y; }}

/** 当窗口大小改变时,通知OpenGL调整大小 */void GLWindow::ReshapeGL(){ GLsizei width = GetWidth(); GLsizei height = GetHeight(); glViewport(0, 0, width, height); /**< 重新设置视口 */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(.0f, (GLfloat)width / (GLfloat)height, 1.0f, .0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); }

/** 改变窗口的显示设置 */bool GLWindow::ChangeScreenSetting(){ DEVMODE dmScreenSettings; /**< 设备模式 */ ZeroMemory(&dmScreenSettings, sizeof(DEVMODE)); /**< 清零结构 */ dmScreenSettings.dmSize = sizeof(DEVMODE); /**< 结构大小 */ dmScreenSettings.dmPelsWidth = GetWidth(); /**< 设置宽度 */ dmScreenSettings.dmPelsHeight = GetHeight(); /**< 设置高度 */ dmScreenSettings.dmBitsPerPel = m_BitsPerPixel; /**< 设置位深度 */ //dmScreenSettings.dmDisplayFrequency = ; /**< 设置屏幕刷新率 */ dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT ;//| DM_DISPLAYFREQUENCY;

/// 改变显示模式 if (ChangeDisplaySettings(&dmScreenSettings, 0) != DISP_CHANGE_SUCCESSFUL) { return false; /**< 如果失败,返回false */ }

return true; /**< 成功返回 */}

/** 创建windows窗口 */bool GLWindow::Create(const char * window_title,const char * class_name,bool fullscreen, HINSTANCE h_instance, LPVOID lpParam){ m_IsFullScreen = fullscreen; int nX=0; int nY=0; PIXELFORMATDESCRIPTOR pfd = /**< 设置像素描述结构 */ { sizeof(PIXELFORMATDESCRIPTOR), /**< 像素描述结构的大小 */ 1, /**< 版本号 */ PFD_DRAW_TO_WINDOW | /**< 缓存区的输出显示在一个窗口中 */ PFD_SUPPORT_OPENGL | /**< 缓存区支持OpenGL绘图 */ PFD_STEREO | /**< 颜色缓存区是立体缓存 */ PFD_DOUBLEBUFFER, /**< 颜色缓存区是双缓存 */ PFD_TYPE_RGBA, /**< 使用RGBA颜色&#;式 */ m_BitsPerPixel, /**< 颜色缓存区中颜色&#;所占的位深 */ 0, 0, 0, 0, 0, 0, /**< 使用默认的颜色设置 */ 0, /**< 无Alpha缓存 */ 0, /**< 颜色缓存区中alpha成分的移位计数 */ 0, /**< 无累计缓存区 */ 0, 0, 0, 0, /**< 累计缓存区无移位 */ , /**< 位深度缓存 */ 0, /**< 无蒙版缓存 */ 0, /**< 无辅助缓存区 */ PFD_MAIN_PLANE, /**< 必须为PFD_MAIN_PLANE,设置为主绘图层 */ 0, /**< 表示OpenGL实现所支持的上层或下层平面的数量 */ 0, 0, 0 /**< 过时,已不再使用 */ };

DWORD windowStyle = WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX; /**< 定义我们窗口类型,使用常规设定,去掉最大化按钮,并不能改变窗体大小 */ DWORD windowExtendedStyle = WS_EX_APPWINDOW;

if (m_IsFullScreen == true) /**< 如果为全屏模式,尝试转化为全屏模式 */ { if (ChangeScreenSetting() == false) { /**< 全屏模式转换失败,弹出对话框提示,并尝试窗口模式 */ MessageBox(HWND_DESKTOP, "模式转换失败.n在窗口模式下运行.", "Error", MB_OK | MB_ICONEXCLAMATION); m_IsFullScreen = false; /**< 设置为窗口模式 */ } else /**< 如果为窗口模式 */ { ShowCursor(false); /**< 隐藏鼠标 */ windowStyle = WS_POPUP; /**< 设置窗口模式为顶层窗口 */ windowExtendedStyle |= WS_EX_TOPMOST; } }

/// 调整我们窗口的大小,使其客户区的大小为我们设置的大小 RECT windowRect = {GetPosX(), GetPosY(), GetPosX() &#; GetWidth(), GetPosY() &#; GetHeight()}; if (m_IsFullScreen == false) /**< 在窗口模式下使用 */ { windowExtendedStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; /**< 使窗口具有3D外观 */ int wid = GetSystemMetrics(SM_CXSCREEN); /**< 获取当前屏幕宽 */ int hei = GetSystemMetrics(SM_CYSCREEN); /**< 获取当前屏幕高 */ nX = (wid - GetWidth()) / 2; /**< 计算窗口居中用 */ nY = (hei - GetHeight()) / 2; /// 调整我们窗口的大小,使其客户区的大小为我们设置的大小 AdjustWindowRectEx(&windowRect, windowStyle, 0, windowExtendedStyle); /// 判断窗口的左上角是否隐藏在桌面外 if (windowRect.left < 0) /**< 如果窗口X坐标为负,移动坐标到0处,并调整窗口的位置 */ { windowRect.right -= windowRect.left; windowRect.left = 0; } if (windowRect.top < 0) /**< 如果窗口Y坐标为负,移动坐标到0处,并调整窗口的位置 */ { windowRect.bottom -= windowRect.top; windowRect.top = 0; } }

/// 创建窗口 m_hWnd = CreateWindowEx(windowExtendedStyle, /**< 窗口的扩展风&#; */ class_name, /**< 窗口的类名 */ window_title, /**< 窗口标题 */ windowStyle, /**< 窗口的风&#; */ nX,nY, /**< 窗口的左上角位置 */ windowRect.right - windowRect.left, /**< 窗口的宽度 */ windowRect.bottom - windowRect.top, /**< 窗口的高度 */ HWND_DESKTOP, /**< 窗口的父窗口为桌面 */ 0, /**< 无菜单 */ h_instance, /**< 传入窗口的实例句柄 */ lpParam); /**< 传入程序类参数 */

while (m_hWnd != 0) /**< 窗口是否创建成功 */ { m_hDC = GetDC(m_hWnd); /**< 返回窗口的设备描述表 */ if (m_hDC == 0) /**< 如果为空 */ { /**< 失败 */ break; }

GLuint PixelFormat = ChoosePixelFormat(m_hDC, &pfd); /**< 查找一个兼容的像素&#;式 */ if (PixelFormat == 0) /**< 如果没找到 */ { /**< 失败 */ break; } if (SetPixelFormat(m_hDC, PixelFormat, &pfd) == false) /**< 设置像素&#;式 */ { /**< 失败 */ break; } m_hRC = wglCreateContext(m_hDC); /**< 创建OpenGL的渲染描述表 */ if (m_hRC == 0) /**< 如果为空 */ { /**< 失败 */ break; } if (wglMakeCurrent(m_hDC, m_hRC) == false) /**< 设置当前的OpenGL的渲染对象为当前的窗口 */ { /**< 失败 */ break; } ShowWindow(m_hWnd, SW_NORMAL); /**< 显示窗口 */ ReshapeGL(); /**< 告诉OpenGL调整窗口大小 */ return true; /**< 成功返回 */ }

Destroy(); /**< 释放资源 */ return false; /**< 返回失败 */}

/** 删除OpenGL窗口 */void GLWindow::Destroy() { if (m_hWnd != 0) /**< 窗口句柄是否存在 */ { if (m_hDC != 0) /**< 窗口设备描述表是否存在 */ { wglMakeCurrent(m_hDC, 0); /**< 设置当前的OpenGL的渲染对象为空NULL */ if (m_hRC != 0) /**< OpenGL的渲染描述表是否存在 */ { wglDeleteContext(m_hRC); /**< 释放OpenGL的渲染描述表 */ m_hRC = 0; /**< 设置OpenGL的渲染描述表为0 */ } ReleaseDC(m_hWnd, m_hDC); /**< 释放窗口的设备描述表 */ m_hDC = 0; /**< 设置窗口的设备描述表为0 */ } DestroyWindow(m_hWnd); /**< 删除窗口 */ m_hWnd = 0; /**< 设置窗口句柄为0 */ }

if (m_IsFullScreen) /**< 如果为全屏模式,在程序结束后,变换到窗口模式,并显示鼠标 */ { ChangeDisplaySettings(NULL, 0); /**< 变换到窗口模式 */ ShowCursor(true); /**< 显示鼠标 */ }}

//=========================================================================/*** @file SkyAndTerrain.cpp** 项目描述: 构造天空和地面* 文件描述: 具体实例类 * 适用平台: Windows//NT/XP* ** 在这个类中您必须重载如下几个虚函数* * virtual bool Init(); * 执行所有的初始化工作,如果成功函数返回true * * virtual void Uninit(); * 执行所有的卸载工作 * * virtual void Update(DWORD milliseconds); * 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位* * virtual void Draw(); * 执行所有的绘制操作*///=========================================================================#include "stdafx.h"#include "SkyAndTerrain.h"

/** 创建一个程序的实例 */GLApplication * GLApplication::Create(const char * class_name){ SkyTerrain * test = new SkyTerrain(class_name); return reinterpret_cast<GLApplication *>(test);}

/** 构造函数 */SkyTerrain::SkyTerrain(const char * class_name) : GLApplication(class_name){ /// 初始化用户自定义的程序变量 m_Fps = 0; m_RenderMode = true; sp = false; }

/** 初始化OpenGL */bool SkyTerrain::Init() {/** 用户自定义的初始化过程 */ glClearColor(0.0f, 0.0f, 0.0f, 0.5f); glClearDepth(1.0f); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glShadeModel(GL_SMOOTH); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); ResizeDraw(true); /**< 改变OpenGL窗口大小,直接调用子类的函数 */

/** 初始化字体 */ if(!m_Font.InitFont()) MessageBox(NULL,"初始化字体失败!","错误",MB_OK); /** 初始化地形 */ if(!m_Terrain.init()) { MessageBox(NULL,"初始化地形失败!","错误",MB_OK); exit(0); }

/** 初始化天空 */ if(!m_SkyBox.init()) { MessageBox(NULL,"初始化天空失败!","错误",MB_OK); exit(0); }

/** 设置摄像机 */ m_Camera.setCamera( , , , , , , 0, 1, 0);

return true; /**< 成功返回 */}

/** 用户自定义的卸载函数 */void SkyTerrain::Uninit() {}/** 更新摄像机 */void SkyTerrain::UpdateCamera(){ m_Camera.setViewByMouse(); /** 键盘按键响应 */ if(m_Keys.IsPressed(VK_SHIFT)) /**< 按下SHIFT键时加速 */ { m_Camera.setSpeed(0.2f); } if(!m_Keys.IsPressed(VK_SHIFT)) { m_Camera.setSpeed(0.1f); } if(m_Keys.IsPressed(VK_UP) || m_Keys.IsPressed('W')) /**< 向上方向键或'W'键按下 */ m_Camera.moveCamera(m_Camera.getSpeed()); /**< 移动摄像机 */

if(m_Keys.IsPressed(VK_DOWN) || m_Keys.IsPressed('S')) /**< 向下方向键或'S'键按下 */ m_Camera.moveCamera(-m_Camera.getSpeed()); /**< 移动摄像机 */

if(m_Keys.IsPressed(VK_LEFT) || m_Keys.IsPressed('A')) /**< 向左方向键或'A'键按下 */ m_Camera.yawCamera(-m_Camera.getSpeed()); /**< 移动摄像机 */

if(m_Keys.IsPressed(VK_RIGHT) || m_Keys.IsPressed('D')) /**< 向右方向键或'D'键按下 */ m_Camera.yawCamera(m_Camera.getSpeed()); /**< 移动摄像机 */

/** 根据地形高度更新摄像机 */ Vector3 vPos = m_Camera.getPosition(); /**< 得到当前摄像机位置 */ Vector3 vNewPos = vPos;

/** 设置摄像机高度为 地形高度 &#; */ vNewPos.y = (float)m_Terrain.getAveHeight(vPos.x,vPos.z ) &#; ;

/** 得到高度差&#; */ float temp = vNewPos.y - vPos.y;

/** 更新摄像机方向 */ Vector3 vView = m_Camera.getView(); vView.y &#;= temp;

/** 设置摄像机 */ m_Camera.setCamera(vNewPos.x, vNewPos.y, vNewPos.z, vView.x, vView.y, vView.z, 0, 1, 0); }/** 程序更新函数 */void SkyTerrain::Update(DWORD milliseconds) { if (m_Keys.IsPressed(VK_ESCAPE) == true) /**< 按ESC退出 */ { TerminateApplication(); }

/** 用户自定义的更新过程 */ /** 更新摄像机 */ UpdateCamera();

/** 空&#;键切换绘制模式 */ if(m_Keys.IsPressed(VK_SPACE) && !sp) { sp = true; m_RenderMode = !m_RenderMode; if(m_RenderMode) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); else glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); }

if(!m_Keys.IsPressed(VK_SPACE)) sp = false;

if (m_Keys.IsPressed(VK_F1) == true) /**< 按F1切换窗口/全屏模式 */ { ToggleFullscreen(); }

}

/** 计算帧速 */void SkyTerrain::CaculateFrameRate(){ static float framesPerSecond = 0.0f; /**< 保存显示帧数 */ static float lastTime = 0.0f; /**< 记录上次时间 */ float currentTime = GetTickCount() * 0.f; /**< 获得当前时间 */

framesPerSecond&#;&#;; /**< 显示帧数递增1 */ /** 如果时间差大于1.0秒 */ if( currentTime - lastTime > 1.0f ) { lastTime = currentTime; /**< 保存当前时间 */ m_Fps = framesPerSecond; /**< 当前帧数传给m_Fps */ framesPerSecond = 0; /**< 将帧数置零 */ }

}

/** 输出文字信息 */void SkyTerrain::PrintText(){ char string[]; /**< 用于保存输出字符串 */ glPushAttrib(GL_CURRENT_BIT); /**< 保存现有颜色属性信息 */ glColor3f(0.0f,1.0f,1.0f); /**< 设置文字颜色 */ sprintf(string,"当前位置:X=%3.1f Y=%3.1f Speed =%3.1f ", m_Camera.getPosition().x,m_Camera.getPosition().z ,m_Camera.getSpeed()); /**< 字符串赋&#; */ m_Font.PrintText(string,-5.0f,3.5f);

/** 输出帧速 */ CaculateFrameRate(); /**< 计算帧速 */ sprintf(string,"FPS:%d",(int)m_Fps); /**< 字符串赋&#; */ m_Font.PrintText(string, -5.0f,3.0f); /**< 输出字符串 */ glPopAttrib(); }

/** 绘制函数 */void SkyTerrain::Draw() {/** 用户自定义的绘制过程 */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); /** 放置摄像机 */ m_Camera.setLook();

/** 绘制天空 */ m_SkyBox.render(); /** 渲染地形 */ m_Terrain.render(); /** 输出屏幕信息 */ PrintText(); glFlush(); /**< 强制执行所有的OpenGL命令 */}

//========================================================/*** @file SkyBox.cpp** 项目描述: 构造天空和地面* 文件描述: 天空盒类 * 适用平台: Windows//NT/XP* **/ //========================================================

#include "SkyBox.h"

CSkyBox::CSkyBox():length(.0f),width(.0f),height(.0f),yRot(0.f){ }

CSkyBox::~CSkyBox(){ /** 删除纹理对象及其占用的内存 */ for(int i =0 ;i< 5; i&#;&#;) { m_texture[i].FreeImage(); glDeleteTextures(1,&m_texture[i].ID); } }

/** 天空盒初始化 */bool CSkyBox::init(){ char filename[] ; /**< 用来保存文件名 */ char *bmpName[] = { "back","front","top","left","right"}; for(int i=0; i< 5; i&#;&#;) { sprintf(filename,"data/%s",bmpName[i]); strcat(filename,".bmp"); if(!m_texture[i].LoadBitmap(filename)) /**< 载入位图文件 */ { MessageBox(NULL,"装载位图文件失败!","错误",MB_OK); /**< 如果载入失败则弹出对话框 */ exit(0); } glGenTextures(1, &m_texture[i].ID); /**< 生成一个纹理对象名称 */ glBindTexture(GL_TEXTURE_2D, m_texture[i].ID); /**< 创建纹理对象 */ /** 控制滤波 */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); /** 创建纹理 */ gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, m_texture[i].imageWidth, m_texture[i].imageHeight, GL_RGB, GL_UNSIGNED_BYTE, m_texture[i].image); } return true; }

void CSkyBox::render(){ /** 获得场景中光照状态 */ GLboolean lp; glGetBooleanv(GL_LIGHTING,&lp);

m_CameraPos = Camera::GetCamera()->getPosition();

glDisable(GL_LIGHTING); /**< 关闭光照 */ glEnable(GL_TEXTURE_2D);

/** 开始绘制 */ glPushMatrix(); glTranslatef(m_CameraPos.x,m_CameraPos.y,m_CameraPos.z);

glRotatef(yRot,0.0f,1.0f,0.0f); /** 绘制背面 */ glBindTexture(GL_TEXTURE_2D, m_texture[0].ID); glBegin(GL_QUADS); /** 指定纹理坐标和顶点坐标 */ glTexCoord2f(1.0f, 0.0f); glVertex3f( width, -height, -length); glTexCoord2f(1.0f, 1.0f); glVertex3f( width, height, -length); glTexCoord2f(0.0f, 1.0f); glVertex3f( -width, height, -length); glTexCoord2f(0.0f, 0.0f); glVertex3f( -width, -height, -length); glEnd();

/** 绘制前面 */ glBindTexture(GL_TEXTURE_2D, m_texture[1].ID); glBegin(GL_QUADS); /** 指定纹理坐标和顶点坐标 */ glTexCoord2f(1.0f, 0.0f); glVertex3f( -width, -height, length); glTexCoord2f(1.0f, 1.0f); glVertex3f( -width, height, length); glTexCoord2f(0.0f, 1.0f); glVertex3f( width, height, length); glTexCoord2f(0.0f, 0.0f); glVertex3f( width, -height, length);

glEnd();

/** 绘制顶面 */ glBindTexture(GL_TEXTURE_2D, m_texture[2].ID); glBegin(GL_QUADS); /** 指定纹理坐标和顶点坐标 */ glTexCoord2f(0.0f, 1.0f); glVertex3f( width, height, -length); glTexCoord2f(0.0f, 0.0f); glVertex3f( width, height, length); glTexCoord2f(1.0f, 0.0f); glVertex3f( -width, height, length); glTexCoord2f(1.0f, 1.0f); glVertex3f( -width, height, -length); glEnd();

/** 绘制左面 */ glBindTexture(GL_TEXTURE_2D, m_texture[3].ID); glBegin(GL_QUADS); /** 指定纹理坐标和顶点坐标 */ glTexCoord2f(1.0f, 1.0f); glVertex3f( -width, height, -length); glTexCoord2f(0.0f, 1.0f); glVertex3f( -width, height, length); glTexCoord2f(0.0f, 0.0f); glVertex3f( -width, -height, length); glTexCoord2f(1.0f, 0.0f); glVertex3f( -width, -height, -length); glEnd();

/** 绘制右面 */ glBindTexture(GL_TEXTURE_2D, m_texture[4].ID); glBegin(GL_QUADS);

/** 指定纹理坐标和顶点坐标 */ glTexCoord2f(0.0f, 0.0f); glVertex3f( width, -height, -length); glTexCoord2f(1.0f, 0.0f); glVertex3f( width, -height, length); glTexCoord2f(1.0f, 1.0f); glVertex3f( width, height, length); glTexCoord2f(0.0f, 1.0f); glVertex3f( width, height, -length); glEnd();

glPopMatrix(); /** 绘制结束 */

if(lp) /** 恢复光照状态 */ glEnable(GL_LIGHTING);

glDisable(GL_TEXTURE_2D);

yRot &#;= 0.f; if(yRot > .0f) yRot = 0.0f;

}

/*======================================* @file stdafx.cpp ***/

#include "stdafx.h"

//========================================================/*** @file Terrain.cpp** 项目描述: 构造天空和地面* 文件描述: 地形类 * 适用平台: Windows//NT/XP* */ //========================================================

#include "Terrain.h"#include "CBMPLoader.h"

/** 当前CTerrain指针 */CTerrain* CTerrain::m_pTerrain = NULL;

/** 多重纹理函数指针 */PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL;PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;

/** 构造函数 */CTerrain::CTerrain():m_bDetail(true),m_DetailScale(){ /** 设置地形大小 */ setSize(MAP_WIDTH,CELL_WIDTH); /** 为地形高程分配内存,并初始化 */ m_pHeightMap = new BYTE[m_nWidth * m_nWidth]; for(int i=0; i<m_nWidth * m_nWidth; i&#;&#;) m_pHeightMap[i] = 0;

m_pTerrain = this; }

/** 析构函数 */CTerrain::~CTerrain(){ /** 删除内存和指针 */ if(m_pHeightMap) { delete[] m_pHeightMap; m_pHeightMap = 0; } /** 删除纹理对象及其占用内存 */ for(int i=0; i<2; i&#;&#;) { m_texture[i].FreeImage(); glDeleteTextures(1,&m_texture[i].ID); }

}

/** 初始化雾效 */void CTerrain::initFog(){ float fogColor[4] = { 0.8f,0.8f,0.8f,1.0f }; glEnable(GL_FOG);

glFogi(GL_FOG_MODE,GL_EXP); /** 设置雾效的模式 */ glFogfv(GL_FOG_COLOR,fogColor); /** 指定雾的颜色 */ glFogf(GL_FOG_DENSITY,0.f); /** 设置雾的浓度 */ glFogf(GL_FOG_START,1.0); /** 设置线性雾的开始位置 */ glFogf(GL_FOG_END,.0); /** 设置线性雾的结束位置 */ glHint(GL_FOG_HINT,GL_DONT_CARE); /** 规定雾化效果的质量 */

}

/** 初始化地形 */bool CTerrain::init(){ glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress("glActiveTextureARB"); glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress("glMultiTexCoord2fARB");

if(!glActiveTextureARB || !glMultiTexCoord2fARB) { //输出错误信息 MessageBox(NULL, "不支持多重纹理!", "错误", MB_OK); exit(0); //setDetail(false); }

/** 载入高度文件 */ loadRawFile("data/terrain.raw");

/** 载入纹理 */ loadTexture();

/** 初始化雾效 */ initFog(); return true;}

/** 设置地形大小 */void CTerrain::setSize(unsigned int width, unsigned int cell){ m_nWidth = width; m_nCellWidth = cell; }

/** 获得高度图中高度&#; */int CTerrain::getHeight(int x,int y){ if(!m_pHeightMap) return 0; int xx = x % m_nWidth; int yy = y % m_nWidth; /** 返回当前高度 */ return m_pHeightMap[(xx &#; yy * m_nWidth)];}

/** 获得地面高度 */float CTerrain::getAveHeight(float x,float z){ float CameraX, CameraZ;

CameraX = x / m_nCellWidth; CameraZ = z / m_nCellWidth;

/** 计算高程坐标(Col0, Row0),(Col1, Row1) */ int col0 = int(CameraX); int row0 = int(CameraZ); unsigned int col1 = col0 &#; 1; unsigned int row1 = row0 &#; 1;

/** 确保单元坐标不超过高程以外 */ if (col1 > m_nWidth) col1 = 0; if (row1 > m_nWidth) row1 = 0;

/** 获取单元的四个角的高度 */ float h = (float)(m_pHeightMap[col0*m_nCellWidth &#; row0*m_nCellWidth*m_nWidth]); float h = (float)(m_pHeightMap[col1*m_nCellWidth &#; row0*m_nCellWidth*m_nWidth]); float h = (float)(m_pHeightMap[col1*m_nCellWidth &#; row1*m_nCellWidth*m_nWidth]); float h = (float)(m_pHeightMap[col0*m_nCellWidth &#; row1*m_nCellWidth*m_nWidth]);

/** 计算机摄像机相对于单元&#;的位置 */ float tx = CameraX - int(CameraX); float ty = CameraZ - int(CameraZ);

/** 进行双线性插&#;得到地面高度 */ float txty = tx * ty;

float final_height = h * (1.0f - ty - tx &#; txty) &#; h * (tx - txty) &#; h * txty &#; h * (ty - txty); return final_height;}

/** 载入高度图 */bool CTerrain::loadRawFile(const char* fileName){ FILE *pFile = NULL;

/** 打开文件 */ pFile = fopen( fileName, "rb" );

/** 错误检查 */ if ( pFile == NULL ) { /** 输出错误信息,并返回false */ MessageBox(NULL, "打开高度图文件失败!", "错误", MB_OK); exit(0); }

/** 读取高度图文件 */ fread( m_pHeightMap, 1, m_nWidth*m_nWidth, pFile );

/** 获取错误代码 */ int result = ferror( pFile );

/** 检查错误代码 */ if (result) { MessageBox(NULL, "无法获取高度数据!", "错误", MB_OK); exit(0); } /** 关闭文件,成功返回 */ fclose(pFile); return true;}

/** 设置纹理坐标 */void CTerrain::setTexCoord(float x,float z){ float u = (float)x / (float)m_nWidth; float v = -(float)z / (float)m_nWidth; ///设置地面纹理的纹理坐标 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);

///设置细节纹理的纹理坐标 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);}

/** 载入地面纹理 */bool CTerrain::loadTexture(){ char* fileName[] = {"data/terrain.bmp","data/detail.bmp"}; for(int i=0; i < 2; i&#;&#;) { if(!m_texture[i].LoadBitmap(fileName[i]) ) /**< 载入位图文件 */ { MessageBox(NULL,"装载位图文件失败!","错误",MB_OK); /**< 如果载入失败则弹出对话框 */ exit(0); } glGenTextures(1, &m_texture[i].ID); /**< 生成一个纹理对象名称 */ glBindTexture(GL_TEXTURE_2D, m_texture[i].ID); /**< 创建纹理对象 */ /** 控制滤波 */ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); /** 创建纹理 */ gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, m_texture[i].imageWidth, m_texture[i].imageHeight, GL_RGB, GL_UNSIGNED_BYTE, m_texture[i].image); } return true;

}

/** 渲染地形 */void CTerrain::render(){ int X = 0, Y = 0; float x, y, z; bool bSwitchSides = false;

/** 检查高度图是否有效 */ if(!m_pHeightMap) return;

/** 绑定纹理 */ glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, m_texture[0].ID); /** 渲染细节纹理 */ if(m_bDetail) { glActiveTextureARB(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_2D);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);

glBindTexture(GL_TEXTURE_2D, m_texture[1].ID); /** 变换纹理矩阵 */ glMatrixMode(GL_TEXTURE); glLoadIdentity(); glScalef((float)m_DetailScale, (float)m_DetailScale, 1); glMatrixMode(GL_MODELVIEW); }

/** 绘制三角形带 */ glBegin( GL_TRIANGLE_STRIP );

/** 从行(X)开始循环 */ for ( X = 0; X <= m_nWidth; X &#;= m_nCellWidth ) { /** 检查该列是否需要从相反顺序绘制 */ if(bSwitchSides) { /** 绘制地形的一列 */ for ( Y = m_nWidth; Y >= 0; Y -= m_nCellWidth ) { /** 顶点(X, Y, Z) */ x = X; y = getHeight( X, Y ); z = Y;

/** 指定纹理坐标,并发送顶点 */ //setFogCoord(m_FogDepth, (float)y); setTexCoord( (float)x, (float)z ); glVertex3f(x, y, z);

/** 顶点(X &#; m_nCellWidth, Y, Z) */ x = X &#; m_nCellWidth; y = getHeight( X &#; m_nCellWidth, Y ); z = Y;

/** 指定纹理坐标,并发送顶点 */ //setFogCoord(m_FogDepth, (float)y); setTexCoord( (float)x, (float)z ); glVertex3f(x, y, z); } } else { /** 绘制地形的一列 */ for ( Y = 0; Y <= m_nWidth; Y &#;= m_nCellWidth ) { /** 顶点(X &#; m_nCellWidth, Y, Z) */ x = X &#; m_nCellWidth; y = getHeight( X &#; m_nCellWidth, Y ); z = Y;

/** 指定纹理坐标,并发送顶点 */ //setFogCoord(m_FogDepth, (float)y); setTexCoord( (float)x, (float)z ); glVertex3f(x, y, z);

/** 顶点 (X, Y, Z) */ x = X; y = getHeight( X, Y ); z = Y;

/** 指定纹理坐标,并发送顶点 */ //setFogCoord(m_FogDepth, (float)y); setTexCoord( (float)x, (float)z ); glVertex3f(x, y, z); } } /** 变换开关 */ bSwitchSides = !bSwitchSides; }

/** 绘制结束 */ glEnd();

///关闭纹理单元1 glActiveTextureARB(GL_TEXTURE1_ARB); glDisable(GL_TEXTURE_2D);

//关闭纹理单元0 glActiveTextureARB(GL_TEXTURE0_ARB); glDisable(GL_TEXTURE_2D);

}

//========================================================/*** @file Vector.cpp** 项目描述: 构造天空和地面* 文件描述: 向量类 * 适用平台: Windows//NT/XP**/ //========================================================

#include "Vector.h" /**< 包含头文件 */

/** 计算向量的长度 */inline float Vector3::length(){ return (float)( x * x &#; y * y &#; z * z );}

/** 单位化一向量 */Vector3 Vector3::normalize(){ float len = length(); /**< 计算向量长度 */ if( len == 0 ) len = 1; x = x / len; y = y / len; z = z / len;

return *this;}

/** 点积 */ float Vector3::dotProduct(const Vector3& v){ return ( x * v.x &#; y * v.y &#; z * v.z );}

/** 叉积 */Vector3 Vector3::crossProduct(const Vector3& v){ Vector3 vec;

vec.x = y * v.z - z * v.y; vec.y = z * v.x - x * v.z; vec.z = x * v.y - y * v.x; return vec;}

/** 操作符 &#; */ Vector3 Vector3::operator &#;(const Vector3& v){ Vector3 vec; vec.x = x &#; v.x; vec.y = y &#; v.y; vec.z = z &#; v.z;

return vec;}

/** 操作符 - */ Vector3 Vector3::operator -(const Vector3& v){ Vector3 vec; vec.x = x - v.x; vec.y = y - v.y; vec.z = z - v.z;

return vec;}

/** 操作符 * */ Vector3 Vector3::operator *(float scale){ x = x * scale; y = y * scale; z = z * scale; return *this;}

/** 操作符 / */ Vector3 Vector3::operator /(float scale){ if(scale != 0.0) { x = x / scale; y = y / scale; z = z / scale; } return *this;}

/** 负号 */ Vector3 Vector3::operator -(){ Vector3 vec( - x,- y, - z); return vec;}

OpenGL进阶(十九) - 多光源 从光说起先看一段wiki中对光的定义光是一种人类眼睛可以见的电磁波(可见光谱),视知觉就是对于光的知觉[1]。光只是电磁波谱上的某一段频谱,一

OpenGL ES2.0-iPhone开发-part1 原文链接地址:

OpenGL绘制Bezier曲线 项目要求:–使用鼠标在屏幕中任意设置控制点,并生成曲线–使用鼠标和键盘的交互操作实现对曲线的修改。项目总体介绍本项目利用Bezier曲线生成

标签: opengl绘制地面

本文链接地址:https://www.jiuchutong.com/biancheng/369632.html 转载请保留说明!

上一篇:3D图象算法(转)(3d图形计算器)

下一篇:OpenGL进阶(十九) - 多光源(opengl示例)

  • 报关单境外收货人错了怎么办
  • 设备租赁公司印花税怎么交
  • 税务师考几科几分及格
  • 中国注册税务师协会法律法规库
  • 不能抵扣的增值税进项税额是什么
  • 出口免税产品如何缴纳附加税
  • 发票开错对方已抵扣怎么处理
  • 出租车手撕票可以换成增值税发票吗
  • 购入股票作为短期投资是什么凭证
  • 餐饮增值税发票抵扣
  • 印花税票吧
  • 电子发票的有效性在哪里查看
  • 什么费用可以报销工会经费
  • 房屋买卖终止协议
  • 交易性金融资产有哪些
  • 未开票收入改为开票收入做账
  • 土地出让金抵减销项税如何申报
  • 企业债务重组损失的所得税前扣除
  • 从联营企业分回利润可以在税前扣除吗
  • 企业留存收益包括盈余公积和未分配利润
  • 营改增对金融服务业税负的影响
  • 小规模企业的企业所得税怎么交
  • 水利建设基金按什么基数计算
  • 内部调拨账务处理
  • 飞鱼星路由器信号有点差怎么办
  • 闲置设备怎么处理
  • 转包工程款怎么结算
  • 其他应收款超过一年是12个月吗?
  • 勃朗峰峡谷
  • symfony框架的特点
  • 会计核算方法体系构成
  • uniapp按钮
  • Pinia(二)了解和使用Store
  • 增值税专用发票和普通发票的区别
  • tokenall
  • 财务人离职了怎么说
  • html基础网页
  • pytorch torch
  • python 动态
  • 零税率和免税的含义和区别
  • 收据能抵成本吗
  • 准则规定的内容是
  • 企业所得税年报更正申报怎么操作
  • 发票上密码区数字什么意思
  • 增值税专用发票怎么开
  • 百旺 税控盘
  • sql server 2008简介
  • 好用的测试工具
  • 公司发行可转债是利好还是利空
  • 异常凭证进项税额转出怎么申报
  • 利润分配账务处理例题
  • 公司房租发票是法人名字能入账吗安全吗
  • 估价入库怎么记账
  • 新公司固定资产盘点总结
  • 行政事业单位零星维修相关规定
  • 支付返利计入什么科目
  • 销售收入确认后怎么处理
  • 业务招待费纳税调整会计分录
  • 小企业会计准则以前年度损益调整
  • 固定资产清理期末
  • record关键字
  • 远程连接局域网电脑
  • win2000蓝屏0x0000007b
  • win sth
  • 大白菜U盘安装原版XP系统教程精细版
  • windows右下角
  • xp系统1
  • win7小键盘怎么调出
  • windows 7如何连接
  • 五步轻松实现zTree的使用
  • 举例说明Java实现适配器模式
  • js+html
  • mac上安装破解软件会怎样
  • python切片菜鸟教程
  • 用python简单代码
  • 比较常见的电子商务模式
  • listview提高效率
  • jquery的form方法
  • 吉林税务网上办事大厅
  • 法治税务建设工作思路
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设