#include <stdio.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/glext.h>
//创建3个纹理对象
GLuint dayearth;
GLuint nightearth;
GLuint cloudsearth;
//创建二次对象
GLUquadricObj *qobj;
GLfloat xoffset = 0.0;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLUNIFORM3FPROC glUniform3f;
PFNGLUNIFORM1IPROC glUniform1i;
PFNGLACTIVETEXTUREPROC glActiveTexture;
#define printOpenGLError() printOglError(__FILE__, __LINE__)
#define BMP_Header_Length 54
GLuint loadTexture(char *file)
{
GLint width, height,totalBytes;
GLubyte* pixels = 0;
GLuint textureID = 0;
GLint lineByte;
FILE* pFile = fopen(file, "rb");
if( pFile == 0 )
{
printf("Can not open file %s", file);
return 0;
}
fseek(pFile, 0x0012, SEEK_SET);
fread(&width, 4, 1, pFile);
fread(&height, 4, 1, pFile);
fseek(pFile, BMP_Header_Length, SEEK_SET);
lineByte = width * 3;
while( lineByte % 4 != 0 )
{
++lineByte;
}
totalBytes = lineByte * height;
pixels = (GLubyte*)malloc(totalBytes);
if ( pixels == 0 ) {
fclose(pFile);
return 0;
}
if ( fread(pixels, totalBytes, 1, pFile) <= 0 ) {
free(pixels);
fclose(pFile);
return 0;
}
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
free(pixels);
fclose(pFile);
return textureID;
}
/**
* @brief 打印OpenGL错误信息
* @param file 错误所在的文件
* @param line 错误所在的行
* @return 1 OpenGL error
* @return 0 other error
**/
int printOglError(char *file, int line)
{
GLenum glErr;
int retCode = 0;
glErr = glGetError();///获取错误
while (glErr != GL_NO_ERROR)
{
printf("glError in file %s @line %d: %s.\n", file, line, gluErrorString(glErr));
retCode = 1;
glErr = glGetError();///获取下一个错误
}
return retCode;
}
/**
* @brief 打印日志
**/
void printInfoLog(GLhandleARB obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB,
&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog);
printf("%s.\n",infoLog);
free(infoLog);
}
}
char *textFileRead(char *fn)
{
FILE *fp;
char *content = NULL;
int count=0;
if (fn != NULL) {
fp = fopen(fn, "rt");
if (fp != NULL) {
fseek(fp, 0, SEEK_END);
count = ftell(fp);
rewind(fp);
if (count > 0) {
content = (char *)malloc(sizeof(char) * (count+1));
count = fread(content,sizeof(char),count,fp);
content[count] = '\0';
}
fclose(fp);
}
}
return content;
}
//YEAH, YEAH, YEAH ... global vars, this is a freggn demo!
GLhandleARB v,f,p; //Handlers for our vertex, geometry, and fragment shaders
int gw,gh; //Keep track of window width and height
void setShaders()
{
glClearColor(0.0f,0.0f,0.0f,1.0f);
glEnable(GL_DEPTH_TEST);
//分别载入地球的白天,夜晚,云彩光泽纹理
dayearth = loadTexture("Day.bmp");
nightearth = loadTexture("Night.bmp");
cloudsearth = loadTexture("Clouds.bmp");
glUniform3f = (PFNGLUNIFORM3FPROC)wglGetProcAddress("glUniform3f");
glUniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i");
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress ("glGetUniformLocation");
glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");
char *vs = NULL,*fs = NULL;
///创造空白顶点着色器对象并返回其句柄
v = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); ///顶点着色器 v
f = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); ///片元着色器 f
///读取着色器源代码文件
vs = textFileRead("Earth.vert");///顶点着色器源代码字符串
fs = textFileRead("Earth.frag");///片元着色器源代码字符串
///加入到字符串数组
const char * vv = vs;
const char * ff = fs;
/// 将着色器源代码字符串数组提交给空白的着色器
/// glShaderSourceARB() 参数表:
/// GLhandleARB shader --- 着色器
/// GLuint nstrings --- 字符串数组中多少个元素 本例子就只有1个字符串
/// const GLcharARB **strings --- 字符串数组
/// GLint *lengths --- 对应字符串数组的长度数组 NULL表示所有字符串以null结束
glShaderSourceARB(v, 1, &vv,NULL);
glShaderSourceARB(f, 1, &ff,NULL);
///释放字符串所占用的内存空间
free(vs);
free(fs);
///编译源代码
glCompileShaderARB(v);
glCompileShaderARB(f);
///打印日志
printInfoLog(v);
printInfoLog(f);
///创造空白程序对象并返回其句柄
p = glCreateProgramObjectARB();
///将着色器对象附加到程序对象
glAttachObjectARB(p,v);
glAttachObjectARB(p,f);
///链接程序对象 打印日志
glLinkProgramARB(p);
printInfoLog(p);
///安装程序对象
glUseProgramObjectARB(p);
printInfoLog(v);
printInfoLog(f);
printInfoLog(p);
glUniform3f(glGetUniformLocation(p, "LightPosition"), 4.0, 0.0, 0.0 );
//设置纹理单元的一致变量,这里要用glUniform1i
glUniform1i(glGetUniformLocation(p, "EarthDay"), 0 );
glUniform1i(glGetUniformLocation(p, "EarthNight"), 1 );
glUniform1i(glGetUniformLocation(p, "EarthCloudGloss"), 2 );
}
void reshape(int w, int h)
{
float range = 200.0f;
if (0 == h)
h = 1;
glViewport(0,0, w,h);
float aspect = (float)w/h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-range, range, -range/aspect, range/aspect, -range, range);
else
glOrtho(-range*aspect, range*aspect, -range, range, -range, range);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(p);
//把白天的活动纹理单元设置为纹理单元0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, dayearth);
//把夜晚的活动纹理单元设置为纹理单元1
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, nightearth);
//把云彩光泽的活动纹理单元设置为纹理单元2
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, cloudsearth);
//利用二次对象画球,这里使用函数gluSolidSphere画球不行
//因为我们需要为每个顶点指定一个表面法线和一个2D纹理坐标
qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
gluQuadricNormals(qobj, GLU_SMOOTH);
gluQuadricTexture(qobj, GL_TRUE);
glPushMatrix();
//glTranslated(0.0, 0.0, -4.0);
//使地球沿Y轴旋转
glRotatef(xoffset, 1.0, 1.0, 1.0);
gluSphere(qobj, 100.0f, 50, 50);
glPopMatrix();
glutSwapBuffers();
glutPostRedisplay();
xoffset += 0.02f;
if (xoffset >= 360.0f)
{
xoffset -= 360.0f;
}
}
int main(int argc, char* argv[])
{
//初始化GLUT并运行
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(600, 600);
glutCreateWindow("Read bmp");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glewInit();
if (glewIsSupported("GL_VERSION_2_1"))
{
printf("Ready for OpenGL 2.1\n");
}
else
{
printf("OpenGL 2.1 not supported\n");
exit(1);
}
if (GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader && GL_EXT_geometry_shader4)
{
printf("Ready for GLSL - vertex, fragment, and geometry units\n");
}
else
{
printf("Not totally ready :( \n");
exit(1);
}
setShaders();
glutMainLoop();
return 0;
}
//Earth.vert
varying float Diffuse;
varying vec3 Specular;
varying vec2 TexCoord;
uniform vec3 LightPosition;
void main(void)
{
vec3 ecPosition = vec3 (gl_ModelViewMatrix * gl_Vertex);
vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal);
vec3 lightVec = normalize(LightPosition - ecPosition);
vec3 reflectVec = reflect(-lightVec, tnorm);
vec3 viewVec = normalize(-ecPosition);
float spec = clamp(dot(reflectVec, viewVec), 0.0, 1.0);
spec = pow(spec, 8.0);
Specular = vec3 (spec) * vec3 (1.0, 0.941, 0.898) * 0.3;
Diffuse = max(dot(lightVec, tnorm), 0.0);
TexCoord = gl_MultiTexCoord0.st;
gl_Position = ftransform();
}
//Earth.frag
uniform sampler2D EarthDay;
uniform sampler2D EarthNight;uniform sampler2D EarthCloudGloss;
varying float Diffuse;
varying vec3 Specular;
varying vec2 TexCoord;
void main (void)
{
vec2 clouds = texture2D(EarthCloudGloss, TexCoord).rg;
vec3 daytime = (texture2D(EarthDay, TexCoord).rgb * Diffuse +
Specular * clouds.g) * (1.0 - clouds.r) +
clouds.r * Diffuse;
vec3 nighttime = texture2D(EarthNight, TexCoord).rgb *
(1.0 - clouds.r) * 2.0;
vec3 color = daytime;
if (Diffuse <= 0.1)
color = mix(nighttime, daytime, (Diffuse + 0.1) * 5.0);
gl_FragColor = vec4 (color, 1.0);
}
调试结果如下