Добавил:
Studfiles2
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Тихомиров Ю. Программирование трёхмерной графики / Files / Lighting / LightingView
.cpp// LightingView.cpp : implementation of the COpenGLView class
//
#include "stdafx.h"
#include "Lighting.h"
#include "LightDlg.h"
#include "Unitdisk.h"
#include "LightingDoc.h"
#include "LightingView.h"
#include "Light.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const float M_2PI = 2.0 * M_PI;
int listSquare;
int listsShadows;
int listsRefraction;
int listSphere = 4;
int listsLights = 5;
int listLightsOn = 6;
int listLightsOff = 7;
int listLightDraw = 8;
int listSpheredisk = 9;
GLfloat CLightingView::aspect = 1.0;
GLfloat CLightingView::eyep[3] = {-6.0, 0.0, 6.0};
GLfloat CLightingView::lookp[3] = { 0.0, 0.0, 1.0};
Color worldAmbient(0.5, 0.5, 0.5);
GLfloat CLightingView::squareAmbient[4] = {0.25, 0.25, 0.25, 1.0};
GLfloat CLightingView::squareDiffuse[4] = {1.0, 1.0, 1.0, 1.0};
GLfloat CLightingView::squareSpecular[4] = {0.0, 0.0, 0.0, 1.0};
const GLfloat sphereAmbient[4] = {0, 0, 0, 0};
const GLfloat sphereSpecular[4] = {0, 0, 0, 0};
const int defDivisionsIndex = 1;
int possibleDivisions[] = {10, 20, 30, 40};
int CLightingView::Diskdiv = possibleDivisions[defDivisionsIndex];
GLfloat index = indices[defRefractionIndex].index;
float CLightingView::dtheta[nLights] = {0, 0, 0};
inline float rand(float min, float max)
{
double r;
r = (double)rand() / (double)RAND_MAX;
return (float)(min + r * (max - min));
}
inline double degrees_clamp(double a)
{
while (a < 0.0) a += 360.0;
while (a > 360.0) a -= 360.0;
return a;
}
double degrees(double a)
{
return (a * 180.0 / M_PI);
}
/////////////////////////////////////////////////////////////////////////////
// CLightingView
IMPLEMENT_DYNCREATE(CLightingView, COpenGLView)
CLightingView::CLightingView()
{
m_pDlg = NULL;
}
CLightingView::~CLightingView()
{
}
BEGIN_MESSAGE_MAP(CLightingView, COpenGLView)
//{{AFX_MSG_MAP(CLightingView)
ON_WM_SIZE()
ON_UPDATE_COMMAND_UI(ID_ROTATE, OnUpdateRotate)
ON_COMMAND(ID_ROTATE, OnRotate)
ON_WM_TIMER()
ON_COMMAND(ID_CUSTIMIZE, OnCustimize)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CLightingView diagnostics
#ifdef _DEBUG
void CLightingView::AssertValid() const
{
CView::AssertValid();
}
void CLightingView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CLightingDoc* CLightingView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CLightingDoc)));
return (CLightingDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CLightingView drawing
void CLightingView::OnInitialUpdate()
{
int i;
char *names[] = {"Красный", "Зеленый", "Синий"};
GLboolean masks[][4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}};
GLfloat diffs[][4] = {{1, 0, 0, 1}, {0, 1, 0, 1}, {0, 0, 1, 1}};
Point posit[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
GLfloat posSphere[] = {0.0, 0.0, 1.0};
GLfloat lightInitRot[] = {-135.0, 0.0, 90.0};
GLfloat lightInitPos[][4] = {
{1.5, 0.0, 2.5, 1.0},
{1.0, 0.0, 3.0, 1.0},
{2.0, 0.0, 3.0, 1.0}
};
COpenGLView::OnInitialUpdate();
drawSphere = GL_TRUE;
drawSquare = GL_TRUE;
drawRefraction = GL_TRUE;
drawShadows = GL_TRUE;
drawLights = GL_TRUE;
m_bRotate = FALSE;
m_Spherediv = 0;
m_pSpherePoints = NULL;
m_SphereSize = 0.5;
m_SpherePosition = posSphere;
white.c[0] = white.c[1] = white.c[2] = white.c[3] = 1.0;
black.c[0] = black.c[1] = black.c[2] = 0.0;
black.c[3] = 1.0;
for(i = 0; i < nLights; i++){
m_lights[i].m_pOwner = this;
m_lights[i].Init((UINT)i, GL_TRUE, names[i],
masks[i], posit[i], diffs[i]);
}
listsInit();
for (i = 0; i < nLights; i++) {
m_lights[i].m_Pos = lightInitPos[i];
m_lights[i].m_LightRotation = lightInitRot[i];
m_lights[i].InitPosition();
}
divisionChange(possibleDivisions[defDivisionsIndex]);
InitOnOff();
for(i = 0; i < nLights; i++)
m_lights[i].InitPosition();
lightsInit();
glClearStencil(0);
// Определяем цвет фона используемый по умолчанию
::glClearColor(1.0f, 0.96f, 0.866f, 1.0f);
}
void CLightingView::OnDraw(CDC* pDC)
{
CLightingDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// Здесь размещается код рисования
sceneDraw();
}
/////////////////////////////////////////////////////////////////////////////
// CLightingView message handlers
void CLightingView::OnSize(UINT nType, int cx, int cy)
{
COpenGLView::OnSize(nType, cx, cy);
m_winx = cx;
m_winy = cy;
glViewport(0, 0, m_winx, m_winy);
aspect = (GLfloat)m_winx / (GLfloat)m_winy;
}
void CLightingView::listsInit()
{
listSquare = glGenLists(1);
listsShadows = glGenLists(nLights);
listsRefraction = glGenLists(nLights);
listsLights = glGenLists(nLights);
listSphere = glGenLists(1);
listSpheredisk = glGenLists(1);
listLightsOn = glGenLists(1);
listLightsOff = glGenLists(1);
listLightDraw = glGenLists(1);
}
void CLightingView::divisionChange(int divisions)
{
int i;
Point eye, look;
if (divisions != m_Spherediv) {
m_Spherediv = divisions;
lightDrawListInit();
for(i = 0; i < nLights; i++)
m_lights[i].listInit();
m_Spheredisk.set_divisions(m_Spherediv, m_Spherediv);
m_Spheredisk.fill_points();
m_Spheredisk.set_colors(white);
m_Spheredisk.scale_alpha_by_z();
eye = eyep;
look = lookp;
m_Spheredisk.face_direction((eye - look).unit());
m_Spheredisk.copy_normals_from_points();
m_Spheredisk.scale_translate(m_SphereSize, m_SpherePosition);
sphereBuild();
sphereListInit();
Diskdiv = divisions;
for(i = 0; i < nLights; i++){
diskBuild(i);
shadowRefractionFullBuild(i);
}
squareListInit();
//spherediskListInit();
for(i = 0; i < nLights; i++){
shadowListInit(i);
refractionListInit(i);
}
}
}
void CLightingView::squareListInit()
{
GLfloat x, y, inc;
int i, j;
glNewList(listSquare, GL_COMPILE);
glLoadName(nameSquare);
glNormal3f(0, 0, 1);
glEnable(GL_LIGHTING);
glCallList(listLightsOn);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, squareAmbient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, squareDiffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, squareSpecular);
inc = (GLfloat) (10.0 / Diskdiv);
glEnable(GL_CULL_FACE);
for(i = 0, y = -5.0; i < Diskdiv; i++, y += inc){
glBegin(GL_TRIANGLE_STRIP);
for (j = 0, x = -5.0; j <= Diskdiv; j++, x += inc) {
glTexCoord2f(x, y + inc);
glVertex2f(x, y + inc);
glTexCoord2f(x, y);
glVertex2f(x, y);
}
glEnd();
}
glDisable(GL_CULL_FACE);
glCallList(listLightsOff);
glDisable(GL_LIGHTING);
glEndList();
}
void CLightingView::sceneDraw()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
sceneProject();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
sceneRasterize();
sceneDrawRefracted();
::SwapBuffers(::wglGetCurrentDC());
}
void CLightingView::sceneProject()
{
glMatrixMode(GL_PROJECTION);
gluPerspective(45, aspect, 0.01, 20.0);
gluLookAt(eyep[0], eyep[1], eyep[2],
lookp[0], lookp[1], lookp[2],
1, 0, 0);
}
void CLightingView::sceneRasterize()
{
int i;
if(drawSquare){
glCallList(listSquare);
}
if(drawShadows)
for(i = 0; i < nLights; i++)
if(m_lights[i].m_On){
glPushMatrix();
glRotatef(-m_lights[i].m_LightRotation, 0, 0, 1);
glCallList(listsShadows + i);
glPopMatrix();
}
if(drawRefraction)
for(i = 0; i < nLights; i++)
if(m_lights[i].m_On){
glPushMatrix();
glRotatef(-m_lights[i].m_LightRotation, 0, 0, 1);
glCallList(listsRefraction + i);
glPopMatrix();
}
for(i = 0; i < nLights; i++)
if(drawLights)
glCallList(listsLights + i);
}
void CLightingView::sceneDrawRefracted()
{
int i;
if (!drawSphere) return;
// Рисуем образ сферы в буфер трафарета
glEnable(GL_STENCIL_TEST);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 0x1, 0x1);
glStencilOp(GL_REPLACE, GL_KEEP, GL_REPLACE);
glColorMask(0, 0, 0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
sceneProject();
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCallList(listSphere);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glColorMask(1, 1, 1, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45 * index, aspect, 0.01, 20.0);
gluLookAt(eyep[0], eyep[1], eyep[2], lookp[0], lookp[1], lookp[2],
1, 0, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Устанавливаем параметры трафарета, которые будут
// использоваться при рисовании образа
glStencilFunc(GL_NOTEQUAL, 0x0, 0xffffffff);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glLoadName(nameSphere);
// Рисуем образ
if(drawSquare)
glCallList(listSquare);
if(drawShadows)
for(i = 0; i < nLights; i++)
if(m_lights[i].m_On){
glPushMatrix();
glRotatef(-m_lights[i].m_LightRotation, 0, 0, 1);
glCallList(listsShadows + i);
glPopMatrix();
}
if(drawRefraction)
for(i = 0; i < nLights; i++)
if(m_lights[i].m_On){
glPushMatrix();
glRotatef(-m_lights[i].m_LightRotation, 0, 0, 1);
glCallList(listsRefraction + i);
glPopMatrix();
}
glDisable(GL_TEXTURE_2D);
// Рисуем сферу
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
sceneProject();
glCallList(listSpheredisk);
glDisable(GL_STENCIL_TEST);
}
void CLightingView::lightsInit()
{
int i;
for (i = 0; i < nLights; i++) {
glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, m_lights[i].m_Diffuse);
glLightfv(GL_LIGHT0 + i, GL_SPECULAR, black.c);
glLightfv(GL_LIGHT0 + i, GL_AMBIENT, black.c);
glLightf(GL_LIGHT0 + i, GL_SPOT_EXPONENT, 4);
glLightf(GL_LIGHT0 + i, GL_SPOT_CUTOFF, 90);
}
glLightfv(GL_LIGHT0 + nLights, GL_DIFFUSE, black.c);
glLightfv(GL_LIGHT0 + nLights, GL_SPECULAR, black.c);
glLightfv(GL_LIGHT0 + nLights, GL_AMBIENT, worldAmbient.c);
glEnable(GL_LIGHT0 + nLights);
// GL_LIGHT0 + nlights + 1 используются для рисования
glLightfv(GL_LIGHT0 + nLights + 1, GL_DIFFUSE, black.c);
glLightfv(GL_LIGHT0 + nLights + 1, GL_SPECULAR, black.c);
glLightfv(GL_LIGHT0 + nLights + 1, GL_AMBIENT, white.c);
}
void CLightingView::lightDrawListInit()
{
float c, s;
int t;
glNewList(listLightDraw, GL_COMPILE);
glEnable(GL_NORMALIZE);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glScalef(.25, .15, .15);
glBegin(GL_QUAD_STRIP);
for(t = 0; t <= m_Spherediv; t++){
c = (float)cos((double)(M_2PI*(float)t/(float)m_Spherediv));
s = (float)sin((double)(M_2PI*(float)t/(float)m_Spherediv));
glNormal3f((GLfloat).25, (GLfloat)(.968*s), (GLfloat)(.968*c));
glVertex3f((GLfloat)0, (GLfloat)s, (GLfloat)c);
glVertex3f((GLfloat)1, (GLfloat)(.75*s), (GLfloat)(.75*c));
}
glEnd();
glNormal3f(1, 0, 0);
glBegin(GL_TRIANGLE_STRIP);
for(t = 0; t <= m_Spherediv; t++){
c = (float)cos((double)(M_2PI*(float)t/(float)m_Spherediv));
s = (float)sin((double)(M_2PI*(float)t/(float)m_Spherediv));
glVertex3f((GLfloat)1, (GLfloat)(.75*s), (GLfloat)(.75*c));
glVertex3f(1, 0, 0);
}
glEnd();
glPopMatrix();
glDisable(GL_NORMALIZE);
glEndList();
}
void CLightingView::sphereBuild()
{
int nSpherepts = (m_Spherediv+1)*m_Spherediv*3;
int r, t, index;
float c, s;
if(m_pSpherePoints != NULL)
delete m_pSpherePoints;
m_pSpherePoints = new GLfloat[nSpherepts];
index = 0;
for (r = 0; r <= m_Spherediv; r++) {
m_pSpherePoints[index++] =
(GLfloat)sin((double)(M_PI*(float)r/(float)m_Spherediv));
m_pSpherePoints[index++] = 0;
m_pSpherePoints[index++] =
(GLfloat)-cos((double)(M_PI*(float)r/(float)m_Spherediv));
}
for (t = 1; t < m_Spherediv; t++) {
c = (float)cos((double)(2.0*M_PI*(float)t/(float)m_Spherediv));
s = (float)sin((double)(2.0*M_PI*(float)t/(float)m_Spherediv));
for (r = 0; r <= m_Spherediv; r++) {
m_pSpherePoints[index++] = c*m_pSpherePoints[r*3];
m_pSpherePoints[index++] = s*m_pSpherePoints[r*3];
m_pSpherePoints[index++] = m_pSpherePoints[r*3 + 2];
}
}
}
void CLightingView::sphereListInit()
{
glNewList(listSphere, GL_COMPILE);
m_Spheredisk.draw_by_perimeter();
glEndList();
}
void CLightingView::diskBuild(int disk)
{
Point light;
light = m_lights[disk].m_Pos;
m_Disks[disk].free_points_normals();
m_Disks[disk].free_colors();
m_Disks[disk].set_divisions(Diskdiv, Diskdiv);
m_Disks[disk].set_angle((float)(2.0 *
acos((double)(m_SphereSize / light.dist(m_SpherePosition)))));
m_Disks[disk].fill_points();
}
void CLightingView::shadowListInit(int n)
{
Color c(squareAmbient[0], squareAmbient[1], squareAmbient[2]);
c *= worldAmbient;
glNewList(listsShadows + n, GL_COMPILE);
glColorMask(m_lights[n].m_ShadowMask[0],
m_lights[n].m_ShadowMask[1],
m_lights[n].m_ShadowMask[2],
m_lights[n].m_ShadowMask[3]);
glDisable(GL_DEPTH_TEST);
glColor3fv(c.c);
m_Shadows[n].draw_by_perimeter(0, 0, 1);
glColorMask(1, 1, 1, 1);
glEndList();
}
void CLightingView::spherediskListInit()
{
glNewList(listSpheredisk, GL_COMPILE);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
glEnable(GL_LIGHTING);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glMaterialfv(GL_AMBIENT, GL_FRONT_AND_BACK, sphereAmbient);
glMaterialfv(GL_SPECULAR, GL_FRONT_AND_BACK, sphereSpecular);
glCallList(listLightsOn);
m_Spheredisk.draw();
glCallList(listLightsOff);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
glEndList();
}
void CLightingView::shadowDraw(int n)
{
}
void CLightingView::refractionListInit(int n)
{
glNewList(listsRefraction + n, GL_COMPILE);
glEnable(GL_LIGHTING);
glCallList(listLightsOff);
// Рассеянный свет белого цвета
glEnable(GL_LIGHT0 + nLights + 1);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, black.c);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black.c);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
glEnable(GL_COLOR_MATERIAL);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
m_Refraction[n].draw();
glDisable(GL_BLEND);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHT0 + nLights + 1);
glDisable(GL_LIGHTING);
glEndList();
}
void CLightingView::shadowRefractionFullBuild(int n)
{
Color c;
float dist_light;
Point dlight, zaxis;
m_Shadows[n].free_points_normals();
m_Shadows[n].free_colors();
m_Refraction[n].free_points_normals();
m_Refraction[n].free_colors();
dlight = m_lights[n].m_Pos - m_SpherePosition;
dist_light = dlight.mag();
dlight.unitize();
zaxis.pt[0] = 0;
zaxis.pt[1] = 0;
zaxis.pt[2] = 1;
m_Shadows[n].set_divisions(m_Disks[n].get_rdivisions(),
m_Disks[n].get_tdivisions());
m_Refraction[n].set_divisions(m_Disks[n].get_rdivisions(),
m_Disks[n].get_tdivisions());
m_Shadows[n].alloc_points();
m_Shadows[n].face_direction(dlight, m_Disks[n]);
m_Shadows[n].scale_translate(m_SphereSize, m_SpherePosition);
c = squareDiffuse;
c *= m_lights[n].m_Diffuse;
m_Refraction[n].copy_points(m_Disks[n]);
m_Refraction[n].set_colors(c);
m_Refraction[n].scale_colors_by_z();
m_Refraction[n].scale(m_SphereSize);
m_Refraction[n].refract_normals(zaxis * dist_light, index);
m_Refraction[n].face_direction(dlight);
m_Refraction[n].project_borrow_points(m_Shadows[n]);
m_Refraction[n].free_normals();
m_Shadows[n].project(m_lights[n].m_Pos);
if(index != 1.0)
m_Refraction[n].scale_colors_by_darea(m_Shadows[n]);
}
void CLightingView::InitOnOff()
{
int i;
glNewList(listLightsOn, GL_COMPILE);
for(i = 0; i < nLights; i++)
if(m_lights[i].m_On)
glEnable(GL_LIGHT0 + i);
else
glDisable(GL_LIGHT0 + i);
glEndList();
glNewList(listLightsOff, GL_COMPILE);
for(i = 0; i < nLights; i++)
glDisable(GL_LIGHT0 + i);
glEndList();
}
void CLightingView::OnUpdateRotate(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(m_bRotate);
}
void CLightingView::OnRotate()
{
m_bRotate = m_bRotate ? FALSE : TRUE;
if (m_bRotate)
SetTimer(1, 15, NULL);
else
KillTimer(1);
}
void CLightingView::OnTimer(UINT nIDEvent)
{
int i;
for(i = 0; i < nLights; i++)
dtheta[i] += rand(-0.5, 0.5);
for(i = 0; i < nLights; i++)
sceneMove(i, 0, 0, dtheta[i] * 0.561, 1);
sceneDraw();
COpenGLView::OnTimer(nIDEvent);
}
int CLightingView::sceneMove(int name, float dr, float dphi, float dtheta, BOOL update)
{
if(name < 0 || name > nLights)
return 0;
return lightsMove(name, dr, dphi, dtheta, update);
}
int CLightingView::lightsMove(int light, float dr, float dphi, float dtheta, BOOL update)
{
float cphi, sphi, x, y;
Point l, dl;
if(!(dr || dphi || dtheta))
return 0;
l = m_lights[light].m_Pos - m_SpherePosition;
if(dr){
dl = l + l*dr;
if(dl.mag() > m_SphereSize)
l = dl;
}
if(dphi){
cphi = (float)cos((double)dphi);
sphi = (float)sin((double)dphi);
y = -l.pt[0]*sphi + l.pt[2]*cphi;
if (y < 2.0*m_SphereSize) {
dphi = (float)atan2((double)(l.pt[2] - 2.0*m_SphereSize), (double)l.pt[0]);
cphi = (float)cos((double)dphi);
sphi = (float)sin((double)dphi);
}
x = l.pt[0];
l.pt[0] = x*cphi + l.pt[2]*sphi;
l.pt[2] = -x*sphi + l.pt[2]*cphi;
}
if(dtheta){
m_lights[light].m_LightRotation +=
(GLfloat)degrees((double)dtheta);
m_lights[light].m_LightRotation =
(GLfloat)degrees_clamp((double)m_lights[light].m_LightRotation);
}
m_lights[light].m_Pos = l + m_SpherePosition;
m_lights[light].m_Pos.pt[3] = 1;
m_lights[light].InitPosition();
m_lights[light].listInit();
if(update)
lightsMoveUpdate(light, dr ? 1 : 0,
dphi ? 1 : 0, dtheta ? 1 : 0);
return 1;
}
void CLightingView::lightsMoveUpdate(int light, int dr, int dphi, int dtheta)
{
if(dr){
diskBuild(light);
shadowRefractionFullBuild(light);
shadowListInit(light);
refractionListInit(light);
}
else
if(dphi){
shadowRefractionFullBuild(light);
shadowListInit(light);
refractionListInit(light);
}
else
if(dtheta){
}
}
void CLightingView::OnCustimize()
{
if(m_pDlg == NULL){
CLightDlg *m_pDlg = new CLightDlg;
m_pDlg->Create(this);
}
}
void CLightingView::lightsOnOff(int which, int bVal)
{
m_lights[which].m_On = bVal;
InitOnOff();
lightsInit();
squareListInit();
}
Соседние файлы в папке Lighting