Использование OpenGL

ПРИЛОЖЕНИЕ Г

Программа имитации освещения Фонга с помощью мультитекстурирования

#include "stdafx.h"
#include "FS.h"
#include "GLScene.h"
#pragma warning(disable: 4305 4309 4244)

CGLScene::CGLScene()
{
	rect.left = 0; rect.right = 640; rect.top = 0 ; rect.bottom = 480;
	texdim = 128;
	objangle[0]   = 0.f; objangle[1]   = 0.f;
	objpos[0]     = 0.f; objpos[1]     = 0.f;
	color[0] = 1.f; color[1] = 1.f; color[2] = 1.f; color[3] = 1.f;
	zero[0]  = 0.f; zero[1]  = 0.f; zero[2]  = 0.f; zero[3]  = 1.f;
	one[0]   = 1.f; one[1]   = 1.f; one[2]   = 1.f; one[3]   = 1.f;
	lighttex = 0;
	lightpos[0] = 0.f; lightpos[1] = 0.f; lightpos[2] = 1.f; lightpos[3] = 0.f;
	lightchanged[0] = GL_TRUE; lightchanged[1] = GL_TRUE;
}

CGLScene::~CGLScene()
{	if (lighttex) delete [] lighttex;	}

void CGLScene::Resize(int cx, int cy)
{
	rect.left  = 0;	 rect.top    = 0;
	rect.right = cx; rect.bottom = cy;
	glViewport(0, 0, rect.right - rect.left, rect.bottom - rect.top);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glFrustum(-100., 100., -100., 100., 300., 600.); 
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0., 0., 450., 0., 0., 0., 0., 1., 0.);
}

void CGLScene::MakeHighlight(int intens)
{
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glPushMatrix(); // предполагаем, что ModelView
	glLoadIdentity();
	glTranslatef(0.f, 0.f, -texdim/2.f);
	
	glMatrixMode(GL_PROJECTION); // подготавливаемся к параллельному проецированию
	glPushMatrix();
	glLoadIdentity();
	glOrtho(-texdim/2., texdim/2., -texdim/2., texdim/2., 0., texdim/2.);
	glPushAttrib(GL_LIGHTING_BIT|GL_VIEWPORT_BIT); // изменяем размеры Viewport'a под размеры текстуры
	glViewport(0, 0, texdim, texdim);
    glEnable(GL_LIGHTING); // включаем освещение
    glLightfv(GL_LIGHT0, GL_DIFFUSE, zero);
    glLightfv(GL_LIGHT0, GL_POSITION, lightpos); // положение источника
    glMateriali(GL_FRONT, GL_SHININESS, intens); // задаём степень светимости
    glMaterialfv(GL_FRONT, GL_AMBIENT, zero);   // остальные параметры -> ноль
    glMaterialfv(GL_FRONT, GL_DIFFUSE, zero); 
    glMaterialfv(GL_FRONT, GL_SPECULAR, color);	// цвет
    glDisable(GL_TEXTURE_2D);

    glCallList(1); // рисуем блик

    glEnable(GL_TEXTURE_2D); // восстанавливаем установки GL
    glPopAttrib();
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glReadPixels(0, 0, texdim, texdim, GL_RGB, GL_FLOAT, lighttex); // читаем содержимое Framebuffer'a
    glBindTexture(GL_TEXTURE_2D, HIGHLIGHT_TEX); // присвоить созданной текстуре идентификатор
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, texdim, texdim, GL_RGB, GL_FLOAT, lighttex);
}

void CGLScene::Render()
{
	objangle[X]+=5.0f; objangle[Y]+=7.0f;
	//objangle[X]=60; objangle[Y]=90;
	static GLfloat ax=0.0f, ay=0.0f, az=0.0f;
	GLfloat ca, sa;
	GLfloat x=lightpos[0], y=lightpos[1], z=lightpos[2];
	ax+=2.0f*M_PI/180.0f; ay+=3.0f*M_PI/180.0f; az+=4.0f*M_PI/180.0f;
	ca=cos(az); sa=sin(az); // вращение вокруг оси OZ
	lightpos[0]=ca - sa;
	lightpos[1]=sa + ca;
	lightchanged[0]=GL_TRUE; lightchanged[1]=GL_TRUE; 
	RenderTexHighlight(); // на каждом кадре - пересчёт блика
}

void CGLScene::RenderTexHighlight()
{
	// положение источника изменилось
	if(lightchanged[UPDATE_TEX]) {
		MakeHighlight(128);
		lightchanged[UPDATE_TEX] = GL_FALSE;
    }
    if(lightchanged[UPDATE_OGL])
    {
		glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
		lightchanged[UPDATE_OGL] = GL_FALSE;
    }
	glPushMatrix(); // предполагаем, что ModelView
	glTranslatef(objpos[X], objpos[Y], 0.f);
	glRotatef(objangle[Y], 0.f, 1.f, 0.f);
	glRotatef(objangle[X], 1.f, 0.f, 0.f);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	// рисуем диффузную составляющую света
      glEnable(GL_LIGHTING);
	glBindTexture(GL_TEXTURE_2D, SURF_TEX);
	glCallList(2);
      glDisable(GL_LIGHTING);
	// блик
glClearColor(0.75, 0.75, 0.75, 1);
	glEnable(GL_BLEND);
	glBindTexture(GL_TEXTURE_2D, HIGHLIGHT_TEX);
	glEnable(GL_TEXTURE_GEN_S);
	glEnable(GL_TEXTURE_GEN_T);
	glDepthFunc(GL_LEQUAL);
	glCallList(2);
	glDepthFunc(GL_LESS);
	glDisable(GL_TEXTURE_GEN_S);
	glDisable(GL_TEXTURE_GEN_T);
	glDisable(GL_BLEND);
	glPopMatrix(); //
	SwapBuffers(wglGetCurrentDC());
	glFlush(); 
}

void CGLScene::PrepareGL()
{
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	// параметры автогенерации координат текстуры
	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); 
	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
	glMateriali(GL_FRONT, GL_SHININESS, 128);
	glCullFace(GL_BACK);
	glBlendFunc(GL_ONE, GL_ONE);
	glEnable(GL_POLYGON_OFFSET_FILL);
	glPolygonOffset(1.0, 1.0);
	lightchanged[UPDATE_TEX] = GL_TRUE;
	lightchanged[UPDATE_OGL] = GL_TRUE;
	// генерируем простую текстуру
	int texwid = 128, texht = 128;
	GLbyte *tex=new GLbyte[texwid * texht * 3];
	GLbyte *ptr=tex;
	for (int i = 0; i < texht; ++i) {
		for (int j = 0; j < texwid; ++j) {
		if ((i ^ j) & 8) {ptr[0] = 0xff; ptr[1] = 0xff; ptr[2] = 0xff;}
		else {ptr[0] = i*512/texht;
			  ptr[1] = j*512/texwid;
			  ptr[2] = 196;}
		ptr += 3;
		}
	}
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, texwid, texht, GL_RGB, GL_UNSIGNED_BYTE, tex);
	delete [] tex;
	lighttex = new GLfloat[texdim * texdim * 3];

	GLUquadricObj *q;
	q=gluNewQuadric();
	glNewList(1, GL_COMPILE);
	gluSphere(q, (GLdouble)texdim/2., 50, 50);// сфера для блика
	glEndList();
	gluDeleteQuadric(q);
	
	GLUquadricObj *quadric = gluNewQuadric();
	gluQuadricTexture(quadric, GL_TRUE);
	glNewList(2, GL_COMPILE);
	gluSphere(quadric, 70., 20, 20);// сфера, выводимая в буфер кадра
	glEndList();
	gluDeleteQuadric(quadric);
	glClearColor(1.0, 1.0, 1.0, 1.0);
}