outdated: 44.3D Lens Flare With Occlusion Testing

这样的光晕如何实现?

其实也就是几个贴图。变着法贴,比如,变大变小贴,变着颜色贴,变着透明度贴,换着距离贴。

下面为代码,其中用到了一些很简单的数学知识。

#ifndef AFX_GLFONT_H__F5069B5F_9D05_4832_8200_1EC9B4BFECE6__INCLUDED_
#define AFX_GLFONT_H__F5069B5F_9D05_4832_8200_1EC9B4BFECE6__INCLUDED_

#include <Windows.h>
#include <GL\glew.h>
#include <GL\glut.h>

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class glFont {
public:
    glFont();
    virtual ~glFont();

public:
    GLuint GetListBase(void);
    GLuint GetTexture(void);
    void SetWindowSize(GLint width, GLint height);
    void glPrintf(GLint x, GLint y, GLint set, const char* Format, ...);
    void BuildFont(GLfloat Scale = 1.0f);
    void SetFontTexture(GLuint tex);                    // Texture ID

protected:
    GLdouble m_WindowWidth;
    GLdouble m_WindowHeight;
    GLuint m_ListBase;
    GLuint m_FontTexture;
};


#endif // !AFX_GLFONT_H__F5069B5F_9D05_4832_8200_1EC9B4BFECE6__INCLUDED_
glFont.h
#include "glFont.h"
#include <stdio.h>
#pragma comment(lib, "legacy_stdio_definitions.lib")

glFont::glFont()
{
    m_FontTexture = 0;
    m_ListBase = 0;
}

glFont::~glFont()
{
    if (m_FontTexture != 0) {
        glDeleteTextures(1, &m_FontTexture);
    }
    if (m_ListBase != 0) {
        glDeleteLists(m_ListBase, 256);
    }
}

void glFont::SetFontTexture(GLuint tex)
{
    if (tex != 0) {
        m_FontTexture = tex;
    }
}

void glFont::BuildFont(GLfloat Scale)
{
    float cx;
    float cy;

    m_ListBase = glGenLists(256);
    if (m_FontTexture != 0) {
        glBindTexture(GL_TEXTURE_2D, m_FontTexture);
        for (GLuint loop = 0; loop < 256; ++loop) {
            cx = float(loop % 16) / 16.0f;
            cy = float(loop / 16) / 16.0f;

            glNewList(m_ListBase + loop, GL_COMPILE);            // Building a list
            glBegin(GL_QUADS);
                glTexCoord2f(cx, 1 - cy - 0.0625f);
                glVertex2f(0, 0);
                glTexCoord2f(cx + 0.0625f, 1 - cy - 0.0625f);
                glVertex2f(16 * Scale, 0);
                glTexCoord2f(cx + 0.0625f, 1 - cy);
                glVertex2f(16 * Scale, 16 * Scale);
                glTexCoord2f(cx, 1 - cy);
                glVertex2f(0, 16 * Scale);
            glEnd();
            glTranslatef(10 * Scale, 0, 0);
            glEndList();
        }
    }
}

void glFont::glPrintf(GLint x, GLint y, GLint set, const char* Format, ...)
{
    char text[256];
    va_list ap;

    if (Format == NULL) {
        return;
    }
    va_start(ap, Format);
    vsprintf(text, Format, ap);
    va_end(ap);

    if (set > 1) {
        set = 1;
    }
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
    glBindTexture(GL_TEXTURE_2D, m_FontTexture);
    glDisable(GL_DEPTH_TEST);
    
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    
    glOrtho(0, m_WindowWidth, 0, m_WindowHeight, -1, 1);           // Set up an ortho screen
    
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    glTranslatef(x, y, 0);
    glListBase(m_ListBase - 32 + (128 * set));
    glCallLists(strlen(text), GL_BYTE, text);
    
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glEnable(GL_DEPTH_TEST);
    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
}

void glFont::SetWindowSize(GLint width, GLint height)
{
    m_WindowWidth = width;
    m_WindowHeight = height;
}

GLuint glFont::GetTexture()
{
    GLuint result = m_FontTexture;
    return result;
}

GLuint glFont::GetListBase()
{
    GLuint result = m_ListBase;
    return result;
}
glFont.cpp
#ifndef AFX_GLVECTOR_H__F526A5CF_89B5_4F20_8F2C_517D83879D35__INCLUDED_
#define AFX_GLVECTOR_H__F526A5CF_89B5_4F20_8F2C_517D83879D35__INCLUDED_

#include <Windows.h>
#include <GL\glew.h>
#include <GL\glut.h>
#include <math.h>

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class glVector {
public:
    glVector();
    virtual ~glVector();

public:
    void operator=(glVector v);
    glVector operator+(glVector v);
    glVector operator*(GLfloat scalar);
    void Normalize(void);
    GLfloat Magnitude(void);
    GLfloat m_Msg;
    void operator*=(GLfloat scalar);
    
    GLfloat i;
    GLfloat j;
    GLfloat k;
};

#endif // !AFX_GLVECTOR_H__F526A5CF_89B5_4F20_8F2C_517D83879D35__INCLUDED_
glVector.h
#include "glVector.h"

glVector::glVector() : i(0), j(0), k(0) {}

glVector::~glVector() {}

void glVector::operator*=(GLfloat scalar)
{
    i *= scalar;
    j *= scalar;
    k *= scalar;
}

GLfloat glVector::Magnitude()
{
    GLfloat result;
    result = GLfloat(sqrt(i * i + j * j + k * k));
    m_Msg = result;
    return result;
}

void glVector::Normalize()
{
    if (m_Msg != 0.0f) {
        i /= m_Msg;
        j /= m_Msg;
        k /= m_Msg;
        Magnitude();
    }
}

glVector glVector::operator*(GLfloat scalar)
{
    glVector r;
    r.i = i * scalar;
    r.j = j * scalar;
    r.k = k * scalar;

    return r;
}

glVector glVector::operator+(glVector v)
{
    glVector r;
    r.i = i + v.i;
    r.j = j + v.j;
    r.k = k + v.k;

    return r;
}

void glVector::operator=(glVector v)
{
    i = v.i;
    j = v.j;
    k = v.k;
    m_Msg = v.m_Msg;
}
glVector.cpp
#ifndef AFX_GLPOINT_H__ADADC708_0176_471A_8241_5DD4D700BCB2__INCLUDED_
#define AFX_GLPOINT_H__ADADC708_0176_471A_8241_5DD4D700BCB2__INCLUDED_

#include <Windows.h>
#include <GL\glew.h>
#include <GL\glut.h>
#include "glVector.h"

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class glPoint {
public:
    glPoint();
    virtual ~glPoint();

public:
    void operator+=(glPoint p);
    glPoint operator+(glPoint p);
    glVector operator-(glPoint p);
    void operator=(glVector v);
    void operator=(glPoint p);

    GLfloat x;
    GLfloat y;
    GLfloat z;
};


#endif // !AFX_GLPOINT_H__ADADC708_0176_471A_8241_5DD4D700BCB2__INCLUDED_
glPoint.h
#include "glPoint.h"

glPoint::glPoint() : x(0), y(0), z(0) {}

glPoint::~glPoint() {}

void glPoint::operator=(glPoint p)
{
    x = p.x;
    y = p.y;
    z = p.z;
}

void glPoint::operator=(glVector v)
{
    x = v.i;
    y = v.j;
    z = v.k;
}

glVector glPoint::operator-(glPoint p)
{
    glVector r;
    r.i = x - p.x;
    r.j = y - p.y;
    r.k = z - p.z;

    return r;
}

glPoint glPoint::operator+(glPoint p)
{
    glPoint r;
    r.x = x + p.x;
    r.y = y + p.y;
    r.z = z + p.z;

    return r;
}

void glPoint::operator+=(glPoint p)
{
    x += p.x;
    y += p.y;
    z += p.z;
}
glPoint.cpp
#ifndef AFX_GLCAMERA_H__8E3CD02E_6D82_437E_80DA_50023C60C146__INCLUDED_
#define AFX_GLCAMERA_H__8E3CD02E_6D82_437E_80DA_50023C60C146__INCLUDED_

#include <windows.h>
#include <GL\glew.h>
#include <gl\glut.h>
#include <math.h>
#include "glVector.h"
#include "glPoint.h"

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class glCamera {
public:
    glCamera();
    virtual ~glCamera();

    BOOL SphereInFrustum(glPoint p, GLfloat Radius);
    BOOL SphereInFrustum(GLfloat x, GLfloat y, GLfloat z, GLfloat Radius);
    BOOL PointInFrustum(GLfloat x, GLfloat y, GLfloat z);
    BOOL PointInFrustum(glPoint p);

    void RenderLensFlare(void);                                  // Render lens flare
    void RenderStreaks(GLfloat r, GLfloat g, GLfloat b, GLfloat a, glPoint p, GLfloat scale);
    void RenderBigGlow(GLfloat r, GLfloat g, GLfloat b, GLfloat a, glPoint p, GLfloat scale);
    void RenderGlow(GLfloat r, GLfloat g, GLfloat b, GLfloat a, glPoint p, GLfloat scale);
    void RenderHalo(GLfloat r, GLfloat g, GLfloat b, GLfloat a, glPoint p, GLfloat scale);

    void UpdateFrustumFaster(void);            // Update the frustum
    void UpdateFrustum(void);

    void ChangeVelocity(GLfloat vel);           // Change volcity and speed
    void ChangeHeading(GLfloat degrees);
    void ChangePitch(GLfloat degrees);
    void SetPrespective(void);

    bool glCamera::IsOccluded(glPoint p);                // Occlusion

    glVector vLightSourceToCamera, vLightSourceToIntersect;
    glPoint ptIntersect, pt;
    GLsizei m_WindowHeight;
    GLsizei m_WindowWidth;
    GLuint m_StreakTexture;
    GLuint m_HaloTexture;
    GLuint m_GlowTexture;
    GLuint m_BigGlowTexture;
    GLfloat m_MaxPointSize;
    GLfloat m_Frustum[6][4];
    glPoint m_LightSourcePos;
    GLfloat m_MaxPitchRate;
    GLfloat m_MaxHeadingRate;
    GLfloat m_HeadingDegrees;
    GLfloat m_PitchDegrees;
    GLfloat m_MaxForwardVelocity;
    GLfloat m_ForwardVelocity;
    glPoint m_Position;
    glVector m_DirectionVector;
};

#endif // !AFX_GLCAMERA_H__8E3CD02E_6D82_437E_80DA_50023C60C146__INCLUDED_
glCamera.h
#include "glCamera.h"

glCamera::glCamera()
{
    m_MaxPitchRate             = 0.0f;
    m_MaxHeadingRate           = 0.0f;
    m_HeadingDegrees           = 0.0f;
    m_PitchDegrees             = 0.0f;
    m_MaxForwardVelocity       = 0.0f;
    m_ForwardVelocity          = 0.0f;
    m_LightSourcePos.x         = 0.0f;
    m_LightSourcePos.y         = 0.0f;
    m_LightSourcePos.z         = 0.0f;
    m_GlowTexture              = 0;
    m_BigGlowTexture           = 0;
    m_HaloTexture              = 0;
    m_StreakTexture            = 0;
    m_MaxPointSize             = 0.0f;
}

glCamera::~glCamera()
{
    if (m_GlowTexture != 0) {
        glDeleteTextures(1, &m_GlowTexture);
    }
    if (m_HaloTexture != 0) {
        glDeleteTextures(1, &m_HaloTexture);
    }
    if (m_BigGlowTexture != 0) {
        glDeleteTextures(1, &m_BigGlowTexture);
    }
    if (m_StreakTexture != 0) {
        glDeleteTextures(1, &m_StreakTexture);
    }
}

void glCamera::SetPrespective()
{
    GLfloat Matrix[16];
    glVector v;

    glRotatef(m_HeadingDegrees, 0.0f, 1.0f, 0.0f);
    glRotatef(m_PitchDegrees, 1.0f, 0.0f, 0.0f);

    glGetFloatv(GL_MODELVIEW_MATRIX, Matrix);

    m_DirectionVector.i = Matrix[8];
    m_DirectionVector.j = Matrix[9];
    m_DirectionVector.k = -Matrix[10];

    glLoadIdentity();

    glRotatef(m_PitchDegrees, 1.0f, 0.0f, 0.0f);
    glRotatef(m_HeadingDegrees, 0.0f, 1.0f, 0.0f);

    // Scale the direction by speed
    v = m_DirectionVector;
    v *= m_ForwardVelocity;

    m_Position.x += v.i;
    m_Position.y += v.j;
    m_Position.z += v.k;

    glTranslatef(-m_Position.x, -m_Position.y, -m_Position.z);
}

void glCamera::ChangePitch(GLfloat degrees)
{
    if (fabs(degrees) < fabs(m_MaxPitchRate)) {
        m_PitchDegrees += degrees;
    }
    else {
        if (degrees < 0) {
            m_PitchDegrees -= m_MaxPitchRate;
        }
        else {
            m_PitchDegrees += m_MaxPitchRate;
        }
    }

    if (m_PitchDegrees > 360.0f) {
        m_PitchDegrees -= 360.0f;
    }
    else if (m_PitchDegrees < -360.0f) {
        m_PitchDegrees += 360.0f;
    }
}

void glCamera::ChangeHeading(GLfloat degrees)
{
    if (fabs(degrees) < fabs(m_MaxHeadingRate)) {
        if ((m_PitchDegrees > 90 && m_PitchDegrees < 270) || 
            (m_PitchDegrees < -90 && m_PitchDegrees > -270))
        {
            m_HeadingDegrees -= degrees;
        }
        else {
            m_HeadingDegrees += degrees;
        }
    }
    else {
        if (degrees < 0) {
            if ((m_PitchDegrees > 90 && m_PitchDegrees < 270) ||
                (m_PitchDegrees < -90 && m_PitchDegrees > -270))
            {
                m_HeadingDegrees += m_MaxHeadingRate;
            }
            else {
                m_HeadingDegrees -= m_MaxHeadingRate;
            }
        }
        else {
            if ((m_PitchDegrees > 90 && m_PitchDegrees < 270) ||
                (m_PitchDegrees < -90 && m_PitchDegrees > -270))
            {
                m_HeadingDegrees -= m_MaxHeadingRate;
            }
            else {
                m_HeadingDegrees += m_MaxHeadingRate;
            }
        }
    }

    if (m_HeadingDegrees > 360.0f)
    {
        m_HeadingDegrees -= 360.0f;
    }
    else if (m_HeadingDegrees < -360.0f)
    {
        m_HeadingDegrees += 360.0f;
    }
}

void glCamera::ChangeVelocity(GLfloat vel)
{
    if (fabs(vel) < fabs(m_MaxForwardVelocity)) {
        m_ForwardVelocity += vel;
    }
    else {
        if (vel < 0) {
            m_ForwardVelocity -= -m_MaxForwardVelocity;
        }
        else {
            m_ForwardVelocity += m_MaxForwardVelocity;
        }
    }
}

void glCamera::UpdateFrustum()
{
    GLfloat clip[16];
    GLfloat proj[16];
    GLfloat modl[16];
    GLfloat t;

    // Get current matrix
    glGetFloatv(GL_PROJECTION_MATRIX, proj);
    glGetFloatv(GL_MODELVIEW_MATRIX, modl);

    // Multiply
    clip[0] = modl[0] * proj[0] + modl[1] * proj[4] + modl[2] * proj[8] + modl[3] * proj[12];
    clip[1] = modl[0] * proj[1] + modl[1] * proj[5] + modl[2] * proj[9] + modl[3] * proj[13];
    clip[2] = modl[0] * proj[2] + modl[1] * proj[6] + modl[2] * proj[10] + modl[3] * proj[14];
    clip[3] = modl[0] * proj[3] + modl[1] * proj[7] + modl[2] * proj[11] + modl[3] * proj[15];

    clip[4] = modl[4] * proj[0] + modl[5] * proj[4] + modl[6] * proj[8] + modl[7] * proj[12];
    clip[5] = modl[4] * proj[1] + modl[5] * proj[5] + modl[6] * proj[9] + modl[7] * proj[13];
    clip[6] = modl[4] * proj[2] + modl[5] * proj[6] + modl[6] * proj[10] + modl[7] * proj[14];
    clip[7] = modl[4] * proj[3] + modl[5] * proj[7] + modl[6] * proj[11] + modl[7] * proj[15];

    clip[8] = modl[8] * proj[0] + modl[9] * proj[4] + modl[10] * proj[8] + modl[11] * proj[12];
    clip[9] = modl[8] * proj[1] + modl[9] * proj[5] + modl[10] * proj[9] + modl[11] * proj[13];
    clip[10] = modl[8] * proj[2] + modl[9] * proj[6] + modl[10] * proj[10] + modl[11] * proj[14];
    clip[11] = modl[8] * proj[3] + modl[9] * proj[7] + modl[10] * proj[11] + modl[11] * proj[15];

    clip[12] = modl[12] * proj[0] + modl[13] * proj[4] + modl[14] * proj[8] + modl[15] * proj[12];
    clip[13] = modl[12] * proj[1] + modl[13] * proj[5] + modl[14] * proj[9] + modl[15] * proj[13];
    clip[14] = modl[12] * proj[2] + modl[13] * proj[6] + modl[14] * proj[10] + modl[15] * proj[14];
    clip[15] = modl[12] * proj[3] + modl[13] * proj[7] + modl[14] * proj[11] + modl[15] * proj[15];

    // Extract the numbers for the right plane
    m_Frustum[0][0] = clip[3] - clip[0];
    m_Frustum[0][1] = clip[7] - clip[4];
    m_Frustum[0][2] = clip[11] - clip[8];
    m_Frustum[0][3] = clip[15] - clip[12];

    // Normal
    t = GLfloat(sqrt(m_Frustum[0][0] * m_Frustum[0][0] + m_Frustum[0][1] * m_Frustum[0][1] +
        m_Frustum[0][2] * m_Frustum[0][2]));
    m_Frustum[0][0] /= t;
    m_Frustum[0][1] /= t;
    m_Frustum[0][2] /= t;
    m_Frustum[0][3] /= t;

    // Extract the numbers for the left plane
    m_Frustum[1][0] = clip[3] + clip[0];
    m_Frustum[1][1] = clip[7] + clip[4];
    m_Frustum[1][2] = clip[11] + clip[8];
    m_Frustum[1][3] = clip[15] + clip[12];

    // Normal
    t = GLfloat(sqrt(m_Frustum[1][0] * m_Frustum[1][0] + m_Frustum[1][1] * m_Frustum[1][1] +
        m_Frustum[1][2] * m_Frustum[1][2]));
    m_Frustum[1][0] /= t;
    m_Frustum[1][1] /= t;
    m_Frustum[1][2] /= t;
    m_Frustum[1][3] /= t;

    // Extract the numbers for the bottm plane
    m_Frustum[2][0] = clip[3] + clip[1];
    m_Frustum[2][1] = clip[7] + clip[5];
    m_Frustum[2][2] = clip[11] + clip[9];
    m_Frustum[2][3] = clip[15] + clip[13];

    // Normal
    t = GLfloat(sqrt(m_Frustum[2][0] * m_Frustum[2][0] + m_Frustum[2][1] * m_Frustum[2][1] +
        m_Frustum[2][2] * m_Frustum[2][2]));
    m_Frustum[2][0] /= t;
    m_Frustum[2][1] /= t;
    m_Frustum[2][2] /= t;
    m_Frustum[2][3] /= t;

    // Extract the numbers for the top plane
    m_Frustum[3][0] = clip[3] - clip[1];
    m_Frustum[3][1] = clip[7] - clip[5];
    m_Frustum[3][2] = clip[11] - clip[9];
    m_Frustum[3][3] = clip[15] - clip[13];

    // Normal
    t = GLfloat(sqrt(m_Frustum[3][0] * m_Frustum[3][0] + m_Frustum[3][1] * m_Frustum[3][1] +
        m_Frustum[3][2] * m_Frustum[3][2]));
    m_Frustum[3][0] /= t;
    m_Frustum[3][1] /= t;
    m_Frustum[3][2] /= t;
    m_Frustum[3][3] /= t;

    // Extract the numbers for the far plane
    m_Frustum[4][0] = clip[3] - clip[2];
    m_Frustum[4][1] = clip[7] - clip[6];
    m_Frustum[4][2] = clip[11] - clip[10];
    m_Frustum[4][3] = clip[15] - clip[14];

    // Normal
    t = GLfloat(sqrt(m_Frustum[4][0] * m_Frustum[4][0] + m_Frustum[4][1] * m_Frustum[4][1] +
        m_Frustum[4][2] * m_Frustum[4][2]));
    m_Frustum[4][0] /= t;
    m_Frustum[4][1] /= t;
    m_Frustum[4][2] /= t;
    m_Frustum[4][3] /= t;

    // Extract the numbers for the near plane
    m_Frustum[5][0] = clip[3] + clip[2];
    m_Frustum[5][1] = clip[7] + clip[6];
    m_Frustum[5][2] = clip[11] + clip[10];
    m_Frustum[5][3] = clip[15] + clip[14];

    // Normal
    t = GLfloat(sqrt(m_Frustum[5][0] * m_Frustum[5][0] + m_Frustum[5][1] * m_Frustum[5][1] +
        m_Frustum[5][2] * m_Frustum[5][2]));
    m_Frustum[5][0] /= t;
    m_Frustum[5][1] /= t;
    m_Frustum[5][2] /= t;
    m_Frustum[5][3] /= t;
}

void glCamera::UpdateFrustumFaster()
{
    GLfloat clip[16];
    GLfloat proj[16];
    GLfloat modl[16];
    GLfloat t;

    glGetFloatv(GL_PROJECTION_MATRIX, proj);
    glGetFloatv(GL_MODELVIEW_MATRIX, modl);

    // Multiply
    // This function will only work if you do not rotate or translate your projection matrix
    clip[0] = modl[0] * proj[0];
    clip[1] = modl[1] * proj[5];
    clip[2] = modl[2] * proj[10] + modl[3] * proj[14];
    clip[3] = modl[2] * proj[11];

    clip[4] = modl[4] * proj[0];
    clip[5] = modl[5] * proj[5];
    clip[6] = modl[6] * proj[10] + modl[7] * proj[14];
    clip[7] = modl[6] * proj[11];

    clip[8] = modl[8] * proj[0];
    clip[9] = modl[9] * proj[5];
    clip[10] = modl[10] * proj[10] + modl[11] * proj[14];
    clip[11] = modl[10] * proj[11];

    clip[12] = modl[12] * proj[0];
    clip[13] = modl[13] * proj[5];
    clip[14] = modl[14] * proj[10] + modl[15] * proj[14];
    clip[15] = modl[14] * proj[11];

    // Extract the numbers for the right plane
    m_Frustum[0][0] = clip[3] - clip[0];
    m_Frustum[0][1] = clip[7] - clip[4];
    m_Frustum[0][2] = clip[11] - clip[8];
    m_Frustum[0][3] = clip[15] - clip[12];

    // Normal
    t = GLfloat(sqrt(m_Frustum[0][0] * m_Frustum[0][0] + m_Frustum[0][1] * m_Frustum[0][1] +
        m_Frustum[0][2] * m_Frustum[0][2]));
    m_Frustum[0][0] /= t;
    m_Frustum[0][1] /= t;
    m_Frustum[0][2] /= t;
    m_Frustum[0][3] /= t;

    // Extract the numbers for the left plane
    m_Frustum[1][0] = clip[3] + clip[0];
    m_Frustum[1][1] = clip[7] + clip[4];
    m_Frustum[1][2] = clip[11] + clip[8];
    m_Frustum[1][3] = clip[15] + clip[12];

    // Normal
    t = GLfloat(sqrt(m_Frustum[1][0] * m_Frustum[1][0] + m_Frustum[1][1] * m_Frustum[1][1] +
        m_Frustum[1][2] * m_Frustum[1][2]));
    m_Frustum[1][0] /= t;
    m_Frustum[1][1] /= t;
    m_Frustum[1][2] /= t;
    m_Frustum[1][3] /= t;

    // Extract the numbers for the bottm plane
    m_Frustum[2][0] = clip[3] + clip[1];
    m_Frustum[2][1] = clip[7] + clip[5];
    m_Frustum[2][2] = clip[11] + clip[9];
    m_Frustum[2][3] = clip[15] + clip[13];

    // Normal
    t = GLfloat(sqrt(m_Frustum[2][0] * m_Frustum[2][0] + m_Frustum[2][1] * m_Frustum[2][1] +
        m_Frustum[2][2] * m_Frustum[2][2]));
    m_Frustum[2][0] /= t;
    m_Frustum[2][1] /= t;
    m_Frustum[2][2] /= t;
    m_Frustum[2][3] /= t;

    // Extract the numbers for the top plane
    m_Frustum[3][0] = clip[3] - clip[1];
    m_Frustum[3][1] = clip[7] - clip[5];
    m_Frustum[3][2] = clip[11] - clip[9];
    m_Frustum[3][3] = clip[15] - clip[13];

    // Normal
    t = GLfloat(sqrt(m_Frustum[3][0] * m_Frustum[3][0] + m_Frustum[3][1] * m_Frustum[3][1] +
        m_Frustum[3][2] * m_Frustum[3][2]));
    m_Frustum[3][0] /= t;
    m_Frustum[3][1] /= t;
    m_Frustum[3][2] /= t;
    m_Frustum[3][3] /= t;

    // Extract the numbers for the far plane
    m_Frustum[4][0] = clip[3] - clip[2];
    m_Frustum[4][1] = clip[7] - clip[6];
    m_Frustum[4][2] = clip[11] - clip[10];
    m_Frustum[4][3] = clip[15] - clip[14];

    // Normal
    t = GLfloat(sqrt(m_Frustum[4][0] * m_Frustum[4][0] + m_Frustum[4][1] * m_Frustum[4][1] +
        m_Frustum[4][2] * m_Frustum[4][2]));
    m_Frustum[4][0] /= t;
    m_Frustum[4][1] /= t;
    m_Frustum[4][2] /= t;
    m_Frustum[4][3] /= t;

    // Extract the numbers for the near plane
    m_Frustum[5][0] = clip[3] + clip[2];
    m_Frustum[5][1] = clip[7] + clip[6];
    m_Frustum[5][2] = clip[11] + clip[10];
    m_Frustum[5][3] = clip[15] + clip[14];

    // Normal
    t = GLfloat(sqrt(m_Frustum[5][0] * m_Frustum[5][0] + m_Frustum[5][1] * m_Frustum[5][1] +
        m_Frustum[5][2] * m_Frustum[5][2]));
    m_Frustum[5][0] /= t;
    m_Frustum[5][1] /= t;
    m_Frustum[5][2] /= t;
    m_Frustum[5][3] /= t;
}

BOOL glCamera::SphereInFrustum(glPoint p, GLfloat Radius)
{
    for (int i = 0; i < 6; ++i) {
        if (m_Frustum[i][0] * p.x + m_Frustum[i][1] * p.y + m_Frustum[i][2] * p.z + m_Frustum[i][3] <= -Radius) {
            return FALSE;
        }
    }
    return TRUE;
}

BOOL glCamera::PointInFrustum(glPoint p)
{
    for (int i = 0; i < 6; ++i) {
        if (m_Frustum[i][0] * p.x + m_Frustum[i][1] * p.y + m_Frustum[i][2] * p.z + m_Frustum[i][3] <= 0) {
            return FALSE;
        }
    }
    return TRUE;
}

BOOL glCamera::SphereInFrustum(GLfloat x, GLfloat y, GLfloat z, GLfloat Radius)
{
    for (int i = 0; i < 6; ++i) {
        if (m_Frustum[i][0] * x + m_Frustum[i][1] * y + m_Frustum[i][2] * z + m_Frustum[i][3] <= -Radius) {
            return FALSE;
        }
    }
    return TRUE;
}

BOOL glCamera::PointInFrustum(GLfloat x, GLfloat y, GLfloat z)
{
    for (int i = 0; i < 6; ++i) {
        if (m_Frustum[i][0] * x + m_Frustum[i][1] * y + m_Frustum[i][2] * z + m_Frustum[i][3] <= 0) {
            return FALSE;
        }
    }
    return TRUE;
}

bool glCamera::IsOccluded(glPoint p)
{
    GLint viewport[4];
    GLdouble mvmatrix[16], projmatrix[16];
    GLdouble winx, winy, winz;
    GLdouble flareZ;                            // The transformed flare Z
    GLfloat bufferZ;                            // The read Z from the buffer

    glGetIntegerv(GL_VIEWPORT, viewport);
    glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
    glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);

    // This asks OGL to guess the 2D position of a 3D point inside the viewport
    gluProject(p.x, p.y, p.z, mvmatrix, projmatrix, viewport, &winx, &winy, &winz);
    flareZ = winz;

    glReadPixels(winx, winy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &bufferZ);

    // If the buffer Z is lower than our flare guessed Z then don't draw
    if (bufferZ < flareZ) {
        return true;
    }
    else {
        return false;
    }
}

void glCamera::RenderLensFlare()
{
    GLfloat Length = 0.0f;

    if (SphereInFrustum(m_LightSourcePos, 1.0f) == TRUE) {
        // Lets compute the vector that points to the camera from the light source
        vLightSourceToCamera = m_Position - m_LightSourcePos;

        Length = vLightSourceToCamera.Magnitude();
        ptIntersect = m_DirectionVector * Length;

        ptIntersect += m_Position;

        // Lets compute the vector that points to the Intersect point from the light source
        vLightSourceToIntersect = ptIntersect - m_LightSourcePos;
        Length = vLightSourceToIntersect.Magnitude();
        vLightSourceToIntersect.Normalize();

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
        glDisable(GL_DEPTH_TEST);
        glEnable(GL_TEXTURE_2D);

        if (!IsOccluded(m_LightSourcePos)) {
            RenderBigGlow(0.60f, 0.60f, 0.8f, 1.0f, m_LightSourcePos, 16.0f);
            RenderStreaks(0.60f, 0.60f, 0.8f, 1.0f, m_LightSourcePos, 16.0f);
            
            RenderGlow(0.8f, 0.8f, 1.0f, 0.5f, m_LightSourcePos, 3.5f);
            /* Lets compute a point that is 20% away from the light source 
            *  in the direction of the intersection point.
            */
            pt = vLightSourceToIntersect * (Length * 0.1f);
            pt += m_LightSourcePos;

            RenderGlow(0.9f, 0.6f, 0.4f, 0.5f, pt, 0.6f);
            /* Lets compute a point that is 30% away from the light source 
            *  in the direction of the intersection point
            */
            pt = vLightSourceToIntersect * (Length * 0.15f);
            pt += m_LightSourcePos;

            RenderHalo(0.8f, 0.5f, 0.6f, 0.5f, pt, 1.7f);

            pt = vLightSourceToIntersect * (Length * 0.175f);  // 35%
            pt += m_LightSourcePos;

            RenderHalo(0.9f, 0.2f, 0.1f, 0.5f, pt, 0.83f);
            pt = vLightSourceToIntersect * (Length * 0.285f);  // 57%
            pt += m_LightSourcePos;

            RenderHalo(0.7f, 0.7f, 0.4f, 0.5f, pt, 1.6f);

            pt = vLightSourceToIntersect * (Length * 0.2755f);  // 55.1%
            pt += m_LightSourcePos;

            RenderGlow(0.9f, 0.9f, 0.2f, 0.5f, pt, 0.8f);

            pt = vLightSourceToIntersect * (Length * 0.4775f);  // 95.5%
            pt += m_LightSourcePos;

            RenderGlow(0.93f, 0.82f, 0.73f, 0.5f, pt, 1.0f);

            pt = vLightSourceToIntersect * (Length * 0.49f);    // 98%
            pt += m_LightSourcePos;

            RenderHalo(0.7f, 0.6f, 0.5f, 0.5f, pt, 1.4f);

            pt = vLightSourceToIntersect * (Length * 0.65f);  // 130%
            pt += m_LightSourcePos;

            RenderGlow(0.7f, 0.8f, 0.3f, 0.5f, pt, 1.8f);

            pt = vLightSourceToIntersect * (Length * 0.63f);  // 126%
            pt += m_LightSourcePos;

            RenderGlow(0.4f, 0.3f, 0.2f, 0.5f, pt, 1.4f);

            pt = vLightSourceToIntersect * (Length * 0.8f);  // 160%
            pt += m_LightSourcePos;

            RenderHalo(0.8f, 0.5f, 0.1f, 0.5f, pt, 0.6f);

            pt = vLightSourceToIntersect * (Length * 1.0f);  // 200%
            pt += m_LightSourcePos;

            RenderGlow(0.5f, 0.5f, 0.7f, 0.5f, pt, 1.7f);

            pt = vLightSourceToIntersect * (Length * 0.975f);  // 195%
            pt += m_LightSourcePos;

            RenderHalo(0.4f, 0.1f, 0.9f, 0.5f, pt, 2.0f);
        }
        glDisable(GL_BLEND);
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_TEXTURE_2D);
    }
}

void glCamera::RenderHalo(GLfloat r, GLfloat g, GLfloat b, GLfloat a, glPoint p, GLfloat scale)
{
    glPoint q[4];

    q[0].x = p.x - scale;
    q[0].y = p.y - scale;

    q[1].x = p.x - scale;
    q[1].y = p.y + scale;

    q[2].x = p.x + scale;
    q[2].y = p.y - scale;

    q[3].x = p.x + scale;
    q[3].y = p.y + scale;

    glPushMatrix();
    glTranslatef(p.x, p.y, p.z);
    glRotatef(-m_HeadingDegrees, 0.0f, 1.0f, 0.0f);
    glRotatef(-m_PitchDegrees, 1.0f, 0.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, m_HaloTexture);
    glColor4f(r, g, b, a);

    glBegin(GL_TRIANGLE_STRIP);
        glTexCoord2f(0.0f, 0.0f);
        glVertex2f(q[0].x, q[0].y);
        glTexCoord2f(0.0f, 1.0f);
        glVertex2f(q[1].x, q[1].y);
        glTexCoord2f(1.0f, 0.0f);
        glVertex2f(q[2].x, q[2].y);
        glTexCoord2f(1.0f, 1.0f);
        glVertex2f(q[3].x, q[3].y);
    glEnd();
    glPopMatrix();
}

void glCamera::RenderGlow(GLfloat r, GLfloat g, GLfloat b, GLfloat a, glPoint p, GLfloat scale)
{
    glPoint q[4];

    q[0].x = p.x - scale;
    q[0].y = p.y - scale;

    q[1].x = p.x - scale;
    q[1].y = p.y + scale;

    q[2].x = p.x + scale;
    q[2].y = p.y - scale;

    q[3].x = p.x + scale;
    q[3].y = p.y + scale;

    glPushMatrix();
    glTranslatef(p.x, p.y, p.z);
    glRotatef(-m_HeadingDegrees, 0.0f, 1.0f, 0.0f);
    glRotatef(-m_PitchDegrees, 1.0f, 0.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, m_GlowTexture);
    glColor4f(r, g, b, a);

    glBegin(GL_TRIANGLE_STRIP);
        glTexCoord2f(0.0f, 0.0f);
        glVertex2f(q[0].x, q[0].y);
        glTexCoord2f(0.0f, 1.0f);
        glVertex2f(q[1].x, q[1].y);
        glTexCoord2f(1.0f, 0.0f);
        glVertex2f(q[2].x, q[2].y);
        glTexCoord2f(1.0f, 1.0f);
        glVertex2f(q[3].x, q[3].y);
    glEnd();
    glPopMatrix();
}

void glCamera::RenderBigGlow(GLfloat r, GLfloat g, GLfloat b, GLfloat a, glPoint p, GLfloat scale)
{
    glPoint q[4];

    q[0].x = p.x - scale;
    q[0].y = p.y - scale;

    q[1].x = p.x - scale;
    q[1].y = p.y + scale;

    q[2].x = p.x + scale;
    q[2].y = p.y - scale;

    q[3].x = p.x + scale;
    q[3].y = p.y + scale;

    glPushMatrix();
    glTranslatef(p.x, p.y, p.z);
    glRotatef(-m_HeadingDegrees, 0.0f, 1.0f, 0.0f);
    glRotatef(-m_PitchDegrees, 1.0f, 0.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, m_BigGlowTexture);
    glColor4f(r, g, b, a);

    glBegin(GL_TRIANGLE_STRIP);
        glTexCoord2f(0.0f, 0.0f);
        glVertex2f(q[0].x, q[0].y);
        glTexCoord2f(0.0f, 1.0f);
        glVertex2f(q[1].x, q[1].y);
        glTexCoord2f(1.0f, 0.0f);
        glVertex2f(q[2].x, q[2].y);
        glTexCoord2f(1.0f, 1.0f);
        glVertex2f(q[3].x, q[3].y);
    glEnd();
    glPopMatrix();
}

void glCamera::RenderStreaks(GLfloat r, GLfloat g, GLfloat b, GLfloat a, glPoint p, GLfloat scale)
{
    glPoint q[4];

    q[0].x = p.x - scale;
    q[0].y = p.y - scale;

    q[1].x = p.x - scale;
    q[1].y = p.y + scale;

    q[2].x = p.x + scale;
    q[2].y = p.y - scale;

    q[3].x = p.x + scale;
    q[3].y = p.y + scale;

    glPushMatrix();
    glTranslatef(p.x, p.x, p.z);
    glRotatef(-m_HeadingDegrees, 0.0f, 1.0f, 0.0f);
    glRotatef(-m_PitchDegrees, 1.0f, 0.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, m_StreakTexture);
    glColor4f(r, g, b, a);

    glBegin(GL_TRIANGLE_STRIP);
        glTexCoord2f(0.0f, 0.0f);
        glVertex2f(q[0].x, q[0].y);
        glTexCoord2f(0.0f, 1.0f);
        glVertex2f(q[1].x, q[1].y);
        glTexCoord2f(1.0f, 0.0f);
        glVertex2f(q[2].x, q[2].y);
        glTexCoord2f(1.0f, 1.0f);
        glVertex2f(q[3].x, q[3].y);
    glEnd();
    glPopMatrix();
}
glCamera.cpp
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <gl/glew.h>
#include <gl/glut.h>
#include <GL/GLUAX.H>
#include <mmsystem.h>
#include "glFont.h"
#include "glCamera.h"

#pragma comment(lib, "legacy_stdio_definitions.lib")
/*
*  Every OpenGL program is linked to a Rendering Context.
*  A Rendering Context is what links OpenGL calls to the Device Context.
*  In order for your program to draw to a Window you need to create a Device Context.
*  The DC connects the Window to the GDI (Graphics Device Interface).
*/

HGLRC     hRC = NULL;         // Permanent rendering context
HDC       hDC = NULL;         // Private GDI device context
HWND      hWnd = NULL;        // Holds our window handle
HINSTANCE hInstance;          // Holds the instance of the application

/*
*  It's important to make this global so that each procedure knows if
*  the program is running in fullscreen mode or not.
*/

bool keys[256];         // Array used for the keyboard routine
bool active = TRUE;     // Window active flag set to TRUE by default
bool fullscreen = TRUE; // Fullscreen flag set to fullscreen mode by default
bool infoOn = FALSE;
int gFrames = 0;
DWORD gStartTime;
DWORD gCurrentTime;
GLfloat gFPS;
glFont gFont;
glCamera gCamera;

GLUquadricObj* qobj;
GLint cylList;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration for WndProc

void DrawGLInfo(void);
void CheckKeys(void);

bool LoadTexture(LPSTR szFileName, GLuint& texid)
{
    HBITMAP hBMP;               // Handle
    BITMAP BMP;                 // Bitmap structure

    glGenTextures(1, &texid);
    hBMP = (HBITMAP)LoadImage(GetModuleHandle(NULL), szFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
    
    if (!hBMP) {
        return FALSE;
    }
    GetObject(hBMP, sizeof(BMP), &BMP);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);        // Pixel storage mode

    glBindTexture(GL_TEXTURE_2D, texid);
    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, 3, BMP.bmWidth, BMP.bmHeight, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
    DeleteObject(hBMP);

    return TRUE;
}

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)   // Resize and initialize the GL window
{
    gCamera.m_WindowHeight = height;
    gCamera.m_WindowWidth = width;

    if (height == 0) {                                // Prevent a divide by zero by
        height = 1;                                   // Making height equal one
    }

    glViewport(0, 0, width, height);                  // Reset the current viewport

    /*
    *  The following lines set the screen up for a perspective view.
    *  Meaning things in the distance get smaller. This creates a realistic looking scene.
    *  The perspective is calculated with a 45 degree viewing angle based on
    *  the windows width and height. The 0.1f, 100.0f is the starting point and
    *  ending point for how deep we can draw into the screen.
    *
    *  The projection matrix is responsible for adding perspective to our scene.
    *  glLoadIdentity() restores the selected matrix to it's original state.
    *  The modelview matrix is where our object information is stored.
    *   Lastly we reset the modelview matrix.
    */

    glMatrixMode(GL_PROJECTION);                      // Select the projection matrix
    glLoadIdentity();                                 // Reset the projection matrix

                                                      // Calculate the aspect ratio of the window
    gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 1.0f, 1000.0f);

    glMatrixMode(GL_MODELVIEW);                       // Seclet the modelview matrix
    glLoadIdentity();                                 // Reset the modelview matrix
}

int InitGL(GLvoid)                                    // All setup for OpenGL goes here
{
    GLuint tex = 0;
    /*
    *  Smooth shading blends colors nicely across a polygon, and smoothes out lighting.
    */

    glShadeModel(GL_SMOOTH);                          // Enables smooth shading
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);             // Black background

    glClearDepth(1.0f);                               // Depth buffer setup

    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);   // Really nice perspective calculations

    LoadTexture("Art/Font.bmp", tex);
    if (tex != 0) {
        gFont.SetFontTexture(tex);
        gFont.SetWindowSize(1024, 768);
        gFont.BuildFont(1.0f);
    }
    else {
        MessageBox(NULL, "Failed to load font texture.", "Error", MB_OK);
    }

    gCamera.m_MaxHeadingRate = 1.0f;
    gCamera.m_MaxPitchRate = 1.0f;
    gCamera.m_HeadingDegrees = 0.0f;

    LoadTexture("Art/HardGlow2.bmp", gCamera.m_GlowTexture);
    if (gCamera.m_GlowTexture == 0) {
        MessageBox(NULL, "Failed to load Hard Glow texture.", "Error", MB_OK);
        return(FALSE);
    }

    LoadTexture("Art/BigGlow3.bmp", gCamera.m_BigGlowTexture);
    if (gCamera.m_BigGlowTexture == 0) {
        MessageBox(NULL, "Failed to load Big Glow texture.", "Error", MB_OK);
        return(FALSE);
    }

    LoadTexture("Art/Halo3.bmp", gCamera.m_HaloTexture);
    if (gCamera.m_HaloTexture == 0) {
        MessageBox(NULL, "Failed to load Halo texture.", "Error", MB_OK);
        return(FALSE);
    }

    LoadTexture("Art/Streaks4.bmp", gCamera.m_StreakTexture);
    if (gCamera.m_StreakTexture == 0) {
        MessageBox(NULL, "Failed to load Streaks texture.", "Error", MB_OK);
        return(FALSE);
    }

    cylList = glGenLists(1);
    qobj = gluNewQuadric();
    gluQuadricDrawStyle(qobj, GLU_FILL);
    gluQuadricNormals(qobj, GLU_SMOOTH);
    glNewList(cylList, GL_COMPILE);
        glEnable(GL_COLOR_MATERIAL);
        glColor3f(0.0f, 0.0f, 1.0f);
        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);
        glTranslatef(0.0f, 0.0f, -2.0f);
//        gluCylinder(qobj, 0.5f, 0.5f, 4.0f, 15, 5);
        glDisable(GL_LIGHTING);
        glDisable(GL_LIGHT0);
        glDisable(GL_COLOR_MATERIAL);
    glEndList();

    gStartTime = timeGetTime();

    return TRUE;
}
/*
*  For now all we will do is clear the screen to the color we previously decided on,
*  clear the depth buffer and reset the scene. We wont draw anything yet.
*/
int DrawGLScene(GLvoid)                                  // Here's where we do all the drawing
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // Clear the screen and the depth buffer
    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, -1.0f);

    gCamera.m_LightSourcePos.z = gCamera.m_Position .z - 50.0f;

    // Pulsing colors based on text position
    // glColor3f(1.0f * float(cos(cnt1)), 1.0f * float(sin(cnt2)), 1.0f - 0.5f * float(cos(cnt1 + cnt2)));
    // Position the text on the screen
    // glRasterPos2f(-0.45f + 0.05f * float(cos(cnt1)), 0.35f * float(sin(cnt2)));
    
    glPushMatrix();
        glLoadIdentity();
        glTranslatef(0.0f, 0.0f, -20.0f);
        glRotatef(timeGetTime() / 50.0f, 0.3f, 0.0f, 0.0f);
        glRotatef(timeGetTime() / 50.0f, 0.0f, 0.5f, 0.0f);
        glCallList(cylList);
    glPopMatrix();
    
    gCamera.SetPrespective();
    gCamera.RenderLensFlare();
    gCamera.UpdateFrustumFaster();

    if (infoOn == TRUE) {
        DrawGLInfo();
    }
    CheckKeys();

    return TRUE;                                         // everthing went OK
}
/*
*  The job of KillGLWindow() is to release the Rendering Context,
*  the Device Context and finally the Window Handle.
*/

GLvoid KillGLWindow(GLvoid)                              // Properly kill the window
{
    if (fullscreen) {                                    // Are we in fullscreen mode

        /*
        *  We use ChangeDisplaySettings(NULL,0) to return us to our original desktop.
        *  After we've switched back to the desktop we make the cursor visible again.
        */

        ChangeDisplaySettings(NULL, 0);                  // if so switch back to the desktop
        ShowCursor(TRUE);                                // Show mouse pointer
    }

    if (hRC) {                                           // Do we have a rendering context
        if (!wglMakeCurrent(NULL, NULL)) {                // Are we able to release the DC and RC contexts
            MessageBox(NULL, "Release of DC and RC failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
        }

        if (!wglDeleteContext(hRC)) {                     // Are we able to delete the RC
            MessageBox(NULL, "Release rendering context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
            hRC = NULL;                                  // Set RC to NULL
        }

        if (hDC && !ReleaseDC(hWnd, hDC)) {              // Are we able to release the DC
            MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
            hDC = NULL;                                  // Set DC to NULL
        }
        if (hWnd && !DestroyWindow(hWnd)) {              // Are we able to destroy the window
            MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
            hWnd = NULL;                                 // Set hWnd to NULL
        }

        if (!UnregisterClass("OpenGL", hInstance)) {     // Are we able to unregister class
            MessageBox(NULL, "Could not register class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
            hInstance = NULL;                            // Set hInstance to NULL
        }
    }
}

/*
* The next section of code creates our OpenGL Window.
*/

BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
    /*
    * Find  a pixel format that matches the one we want
    */
    GLuint PixelFormat;                                  // Holds the result after serching for a match

    /*
    * Before you create a window, you MUST register a Class for the window
    */
    WNDCLASS wc;                                         // Windows class structure

    /*
    *  dwExStyle and dwStyle will store the Extended and normal Window Style Information.
    */
    DWORD dwExStyle;                                     // Window extend style
    DWORD dwStyle;                                       // Window style

    RECT WindowRect;                                     // Grabs rectangle upper left/lower right values
    WindowRect.left = (long)0;                           // Set left value to 0
    WindowRect.right = (long)width;                      // Set right value to requested width
    WindowRect.top = (long)0;                            // Set top value to 0
    WindowRect.bottom = (long)height;                    // Set bottom value to requested height

    fullscreen = fullscreenflag;                         // Set the global fullscreen flag

    /*
    *  The style CS_HREDRAW and CS_VREDRAW force the Window to redraw whenever it is resized.
    *  CS_OWNDC creates a private DC for the Window. Meaning the DC is not shared across applications.
    *  WndProc is the procedure that watches for messages in our program.
    *  No extra Window data is used so we zero the two fields. Then we set the instance.
    *  Next we set hIcon to NULL meaning we don't want an ICON in the Window,
    *  and for a mouse pointer we use the standard arrow. The background color doesn't matter
    *  (we set that in GL). We don't want a menu in this Window so we set it to NULL,
    *  and the class name can be any name you want. I'll use "OpenGL" for simplicity.
    */
    hInstance = GetModuleHandle(NULL);                   // Grab an instance for our window
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;       // Redraw on move, and own DC for window
    wc.lpfnWndProc = (WNDPROC)WndProc;                   // WndProc handles message
    wc.cbClsExtra = 0;                                   // No extra window date
    wc.cbWndExtra = 0;                                   // No extra window date
    wc.hInstance = hInstance;                            // set the instance
    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);              // Load the default icon
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);            // Load the arrow pointer
    wc.hbrBackground = NULL;                             // No background requried for GL
    wc.lpszMenuName = NULL;                              // We don't want a menu
    wc.lpszClassName = "OpenGL";                         // set the class name

    if (!RegisterClass(&wc)) {                           // Attempt to register the window class
        MessageBox(NULL, "Failed to register the window class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                                    // Exit and return false
    }

    if (fullscreen) {                                    // attempt fullsreen model

        /*
        *  There are a few very important things you should keep in mind when switching to full screen mode.
        *  Make sure the width and height that you use in fullscreen mode is the same as
        *  the width and height you plan to use for your window, and most importantly,
        *  set fullscreen mode BEFORE you create your window.
        */
        DEVMODE dmScreenSettings;                        // Device mode
        memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make sure memory's cleared
        dmScreenSettings.dmSize = sizeof(dmScreenSettings);     // Size of devmode structure
        dmScreenSettings.dmPelsWidth = width;            // Select window width
        dmScreenSettings.dmPelsHeight = height;          // Select window height
        dmScreenSettings.dmBitsPerPel = bits;            // Select bits per pixel
        dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

        /*
        *  In the line below ChangeDisplaySettings tries to switch to a mode that matches
        *  what we stored in dmScreenSettings. I use the parameter CDS_FULLSCREEN when switching modes,
        *  because it's supposed to remove the start bar at the bottom of the screen,
        *  plus it doesn't move or resize the windows on your desktop when you switch to
        *  fullscreen mode and back.
        */
        //Try to set selected mode and get results. Note: CDS_FULLSCREEN gets rid of start bar
        if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
            //If the mode fails, offer two options. Quit or run in a window
            if (MessageBox(NULL, "The requested fullscreen mode is not supported by\n your video card. Use"
                "windowed mode instead?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
            {
                fullscreen = FALSE;                       // Select windowed mode (fullscreen=FLASE)
            }
            else {
                // Pop up a message box letting user know the programe is closing.
                MessageBox(NULL, "Program will now close.", "ERROR", MB_OK | MB_ICONSTOP);
                return FALSE;                             // Exit and return FALSE
            }
        }
    }

    if (fullscreen) {                                     // Are we still in fullscreen mode

        /*
        *  If we are still in fullscreen mode we'll set the extended style to WS_EX_APPWINDOW,
        *  which force a top level window down to the taskbar once our window is visible.
        *  For the window style we'll create a WS_POPUP window.
        *  This type of window has no border around it, making it perfect for fullscreen mode.

        *  Finally, we disable the mouse pointer. If your program is not interactive,
        *  it's usually nice to disable the mouse pointer when in fullscreen mode. It's up to you though.
        */
        dwExStyle = WS_EX_APPWINDOW;                      // Window extended style
        dwStyle = WS_POPUP;                               // Window style
        ShowCursor(FALSE);                                // Hide mosue pointer 
    }
    else {

        /*
        *  If we're using a window instead of fullscreen mode,
        *  we'll add WS_EX_WINDOWEDGE to the extended style. This gives the window a more 3D look.
        *  For style we'll use WS_OVERLAPPEDWINDOW instead of WS_POPUP.
        *  WS_OVERLAPPEDWINDOW creates a window with a title bar, sizing border,
        *  window menu, and minimize / maximize buttons.
        */
        dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;   // Window extended style
        dwStyle = WS_OVERLAPPEDWINDOW;                    // Window style
    }

    /*
    *  By using the AdjustWindowRectEx command none of our OpenGL scene will be covered up by the borders,
    *  instead, the window will be made larger to account for the pixels needed to draw the window border.
    *  In fullscreen mode, this command has no effect.
    */
    AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);  // Adjust window to true resqusted

    /*
    *  WS_CLIPSIBLINGS and WS_CLIPCHILDREN are both REQUIRED for OpenGL to work properly.
    *  These styles prevent other windows from drawing over or into our OpenGL Window.
    */
    if (!(hWnd = CreateWindowEx(dwExStyle,                // Extended style for the window
        "OpenGL",                                         // Class name
        title,                                            // Window title
        WS_CLIPSIBLINGS |                                 // Requried window style
        WS_CLIPCHILDREN |                                 // Requried window style
        dwStyle,                                          // Select window style
        0, 0,                                             // Window position
        WindowRect.right - WindowRect.left,               // Calculate adjusted window width
        WindowRect.bottom - WindowRect.top,               // Calculate adjusted window height
        NULL,                                             // No parent window
        NULL,                                             // No menu
        hInstance,                                        // Instance
        NULL)))                                           // Don't pass anything to WM_CREATE
    {
        KillGLWindow();                                   //Reset the display
        MessageBox(NULL, "Window creation error.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                                     // Retrurn FALSE;
    }

    /*
    *  aside from the stencil buffer and the (slow) accumulation buffer
    */
    static PIXELFORMATDESCRIPTOR pfd =                    // pfd tells windows how we want things to be 
    {
        sizeof(PIXELFORMATDESCRIPTOR),                    // Size of this pixel format descriptor
        1,                                                // Version number
        PFD_DRAW_TO_WINDOW |                              // Format must support window
        PFD_SUPPORT_OPENGL |                              // Format must support OpenGL
        PFD_DOUBLEBUFFER,                                 // Must support double buffer
        PFD_TYPE_RGBA,                                    // Request an RGBA format
        bits,                                             // Select our color depth
        0, 0, 0, 0, 0, 0,                                 // Color bits ignored
        0,                                                // No alpha buffer
        0,                                                // shift bit ignored
        0,                                                // No accumulation buffer
        0, 0, 0, 0,                                       // Accumulation bits ignored
        16,                                               // 16Bits Z_Buffer (depth buffer)
        0,                                                // No stencil buffer
        0,                                                // No auxiliary buffer
        PFD_MAIN_PLANE,                                   // Main drawing layer
        0,                                                // Reserved
        0, 0, 0                                           // Layer makes ignored
    };

    if (!(hDC = GetDC(hWnd))) {                           // Did we get a device context
        KillGLWindow();                                   // Reset the display
        MessageBox(NULL, "Can't create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                                     // Return FALSE
    }

    if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) {  // Did window find a matching pixel format
        KillGLWindow();                                   // Reset the display
        MessageBox(NULL, "Can't find a suitable pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                                     // Return FALSE;
    }

    if (!SetPixelFormat(hDC, PixelFormat, &pfd)) {        // Are we able to set the pixel format
        KillGLWindow();                                   // Reset the display
        MessageBox(NULL, "Can't set the pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                                     // Return FALSE;
    }

    if (!(hRC = wglCreateContext(hDC))) {                 // Are we able to rendering context
        KillGLWindow();                                   // Reset the display
        MessageBox(NULL, "Can't create a GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                                     // Return FASLE;
    }

    if (!wglMakeCurrent(hDC, hRC)) {                      // Try to activate the rendering context
        KillGLWindow();                                   // Reset the display
        MessageBox(NULL, "Can't activate the GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                                     // Return FALSE    
    }

    /*
    *  ReSizeGLScene passing the screen width and height to set up our perspective OpenGL screen.
    */
    ShowWindow(hWnd, SW_SHOW);                            // Show the window
    SetForegroundWindow(hWnd);                            // slightly higher priority
    SetFocus(hWnd);                                       // Sets keyboard focus to the window
    ReSizeGLScene(width, height);                         // Set up our perspective GL screen

    /*
    *  we can set up lighting, textures, and anything else that needs to be setup in InitGL().
    */
    if (!InitGL()) {                                      // Initialize our newly created GL window
        KillGLWindow();                                   // Reset the display
        MessageBox(NULL, "Initialize Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                                     // Return FALSE
    }
    return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd,                       // Handle for this window
    UINT uMsg,                                            // Message for this window
    WPARAM wParam,                                        // Additional message information
    LPARAM lParam)                                        // Additional message information
{
    switch (uMsg) {                                       // Check for window message
    case WM_ACTIVATE: {                               // Check minimization state
        if (!HIWORD(wParam)) {
            active = TRUE;                            // Program is active
        }
        else {
            active = FALSE;                           // Program is no longer active
        }
        return 0;                                     // Return to the message loop
    }
    case WM_SYSCOMMAND: {                             // Intercept system commands
        switch (wParam) {                             // Check system calls
        case SC_SCREENSAVE:                       // Screensaver trying to start
        case SC_MONITORPOWER:                     // Monitor trying to enter powersave
            return 0;                                 // Prevent form happening
        }
        break;                                        // Exit
    }
    case WM_CLOSE: {                                  // Did we receive a close message
        PostQuitMessage(0);                           // Send a quit message
        return 0;
    }
    case WM_KEYDOWN: {                                // Is a key being held down
        keys[wParam] = TRUE;                          // if so, mark it as TRUE
        return 0;                                     // Jump back
    }
    case WM_KEYUP: {                                  // Has a key been released
        keys[wParam] = FALSE;                         // if so, mark it as FALSE
        return 0;                                     // Jump back
    }
    case WM_SIZE: {                                   // Resize the OpenGL window
        ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));   // LoWord = width HiWord = height
        return 0;                                     // Jump back
    }
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);     // Pass all unhandled message to DefWindwProc
}

int WINAPI WinMain(HINSTANCE hInstance,                   // Instance
    HINSTANCE hPrevInstance,                              // Previous instance
    LPSTR lpCmdLine,                                      // Command line parameters
    int nCmdShow)                                         // Window show state
{
    MSG msg;                                              // Window message structure
    BOOL done = FALSE;                                    // Bool variable to exit loop
    
    // Ask the user which screen mode they prefer
    if (MessageBox(NULL, "Would you like to run in fullscreen mode?",
        "Start fullscreen?", MB_YESNO | MB_ICONQUESTION) == IDNO)
    {
        fullscreen = FALSE;                               // Window mode
    }
    // Create our OpenGL window
    if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) {  // (Modified)
        return 0;                                         // Quit if window was not create
    }

    while (!done) {                                       // Loop that runs until donw = TRUE
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {   // Is there a message wating
            if (msg.message == WM_QUIT) {                 // Havw we received a quit message
                done = TRUE;                              // if so done  = TRUE
            }
            else {                                        // If not, deal with window message
                TranslateMessage(&msg);                   // Translate message
                DispatchMessage(&msg);                    // Dispatch message
            }
        }
        else {
            // Draw the scene. Watch for ESC key and quit message from DrawGLScene()
            if (active) {                                 // Program active
                if (keys[VK_ESCAPE]) {                    // Was ESC pressed
                    done = TRUE;                          // ESC signalled a quit
                }
                else {                                    // Not time to quit, update screen
                    DrawGLScene();                        // Draw scene
                    SwapBuffers(hDC);                     // Swap buffers (double buffering)
                }
            }

            /*
            *  It allows us to press the F1 key to switch from fullscreen mode to
            *  windowed mode or windowed mode to fullscreen mode.
            */
            if (keys[VK_F1]) {                            // Is F1 being pressed
                keys[VK_F1] = FALSE;                      // If so make key FASLE
                KillGLWindow();                           // Kill our current window
                fullscreen = !fullscreen;                 // Toggle fullscreen / window mode
                                                          //Recreate our OpenGL window(modified)
                if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) {
                    return 0;                             // Quit if window was not create
                }
            }
        }
    }

    gluDeleteQuadric(qobj);
    glDeleteLists(cylList, 1);

    // Shutdown
    KillGLWindow();
    return msg.wParam;
}

void DrawGLInfo(void)
{
    GLfloat modelMatrix[16];             // The model view matrix
    GLfloat projMatrix[16];              // The projection matrix
    GLfloat DiffTime;                    // The difference in time
    char String[64];                     // A temporary string to use to format information

    glGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
    glGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix);

    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    // The cameras position
    sprintf(String, "m_Position............. = %.02f, %.02f, %.02f", 
        gCamera.m_Position.x, gCamera.m_Position.y, gCamera.m_Position.z);
    gFont.glPrintf(10, 720, 1, String);
    // The cameras direction
    sprintf(String, "m_DirectionVector...... = %.02f, %.02f, %.02f", 
        gCamera.m_DirectionVector.i, gCamera.m_DirectionVector.j, gCamera.m_DirectionVector.k);
    gFont.glPrintf(10, 700, 1, String);
    // The light sources position
    sprintf(String, "m_LightSourcePos....... = %.02f, %.02f, %.02f", 
        gCamera.m_LightSourcePos.x, gCamera.m_LightSourcePos.y, gCamera.m_LightSourcePos.z);
    gFont.glPrintf(10, 680, 1, String);
    // The intersection point
    sprintf(String, "ptIntersect............ = %.02f, %.02f, %.02f", 
        gCamera.ptIntersect.x, gCamera.ptIntersect.y, gCamera.ptIntersect.x);
    gFont.glPrintf(10, 660, 1, String);
    // The vector that points from the light source to the camera
    sprintf(String, "vLightSourceToCamera... = %.02f, %.02f, %.02f", 
        gCamera.vLightSourceToCamera.i, gCamera.vLightSourceToCamera.j, gCamera.vLightSourceToCamera.k);
    gFont.glPrintf(10, 640, 1, String);
    // The vector that points from the light source to the intersection point
    sprintf(String, "vLightSourceToIntersect = %.02f, %.02f, %.02f", 
        gCamera.vLightSourceToIntersect.i, gCamera.vLightSourceToIntersect.j, gCamera.vLightSourceToIntersect.k);
    gFont.glPrintf(10, 620, 1, String);
    // The below matrix is the model view matrix
    sprintf(String, "GL_MODELVIEW_MATRIX");
    gFont.glPrintf(10, 580, 1, String);
    // The model view matrix
    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        modelMatrix[0], modelMatrix[1], modelMatrix[2], modelMatrix[3]);
    gFont.glPrintf(10, 560, 1, String);
    
    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        modelMatrix[4], modelMatrix[5], modelMatrix[6], modelMatrix[7]);
    gFont.glPrintf(10, 540, 1, String);

    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        modelMatrix[8], modelMatrix[9], modelMatrix[10], modelMatrix[11]);
    gFont.glPrintf(10, 520, 1, String);

    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        modelMatrix[12], modelMatrix[13], modelMatrix[14], modelMatrix[15]);
    gFont.glPrintf(10, 500, 1, String);

    // The below matrix is the projection matrix
    sprintf(String, "GL_PROJECTION_MATRIX");
    gFont.glPrintf(10, 460, 1, String);

    // The projection view matrix
    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        projMatrix[0], projMatrix[1], projMatrix[2], projMatrix[3]);
    gFont.glPrintf(10, 440, 1, String);

    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        projMatrix[4], projMatrix[5], projMatrix[6], projMatrix[7]);
    gFont.glPrintf(10, 420, 1, String);

    sprintf(String, "%.02f, %.02f, %.03f, %.03f", 
        projMatrix[8], projMatrix[9], projMatrix[10], projMatrix[11]);
    gFont.glPrintf(10, 400, 1, String);

    sprintf(String, "%.02f, %.02f, %.03f, %.03f", 
        projMatrix[12], projMatrix[13], projMatrix[14], projMatrix[15]);
    gFont.glPrintf(10, 380, 1, String);

    // The below values are the Frustum clipping planes
    gFont.glPrintf(10, 320, 1, "FRUSTUM CLIPPING PLANES");

    // The clipping plane
    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        gCamera.m_Frustum[0][0], gCamera.m_Frustum[0][1], gCamera.m_Frustum[0][2], gCamera.m_Frustum[0][3]);
    gFont.glPrintf(10, 300, 1, String);

    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        gCamera.m_Frustum[1][0], gCamera.m_Frustum[1][1], gCamera.m_Frustum[1][2], gCamera.m_Frustum[1][3]);
    gFont.glPrintf(10, 280, 1, String);

    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        gCamera.m_Frustum[2][0], gCamera.m_Frustum[2][1], gCamera.m_Frustum[2][2], gCamera.m_Frustum[2][3]);
    gFont.glPrintf(10, 260, 1, String);

    sprintf(String, "%.02f, %.02f, %.02f, %.02f",
        gCamera.m_Frustum[3][0], gCamera.m_Frustum[3][1], gCamera.m_Frustum[3][2], gCamera.m_Frustum[3][3]);
    gFont.glPrintf(10, 240, 1, String);

    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        gCamera.m_Frustum[4][0], gCamera.m_Frustum[4][1], gCamera.m_Frustum[4][2], gCamera.m_Frustum[4][3]);
    gFont.glPrintf(10, 220, 1, String);

    sprintf(String, "%.02f, %.02f, %.02f, %.02f", 
        gCamera.m_Frustum[5][0], gCamera.m_Frustum[5][1], gCamera.m_Frustum[5][2], gCamera.m_Frustum[5][3]);
    gFont.glPrintf(10, 200, 1, String);

    if (gFrames >= 100) {
        gCurrentTime = timeGetTime();
        DiffTime = GLfloat(gCurrentTime - gStartTime);
        gFPS = (gFrames / DiffTime) * 1000.0f;
        gStartTime = gCurrentTime;
        gFrames = 1;
    }
    else {
        gFrames++;
    }

    sprintf(String, "FPS %.02f", gFPS);
    gFont.glPrintf(10, 160, 1, String);
}

void CheckKeys(void)
{
    if (keys['S'] == TRUE) {
        gCamera.ChangePitch(-0.05f);
    }

    if (keys['W'] == TRUE) {
        gCamera.ChangePitch(0.05f);
    }

    if (keys['A'] == TRUE) {
        gCamera.ChangeHeading(0.05f);
    }

    if (keys['D'] == TRUE) {
        gCamera.ChangeHeading(-0.05f);
    }

    if (keys['Z'] == TRUE) {
        gCamera.m_ForwardVelocity = 0.02f;
    }

    if (keys['C'] == TRUE) {
        gCamera.m_ForwardVelocity = -0.02f;
    }

    if (keys['X'] == TRUE) {
        gCamera.m_ForwardVelocity = 0.0f;
    }

    if (keys['1'] == TRUE) {
        infoOn = TRUE;
    }

    if (keys['2'] == TRUE) {
        infoOn = FALSE;
    }
}
Main.cpp

Thanks for Nehe's tutorials, this is his home.

posted @ 2016-10-20 22:47  clairvoyant  阅读(239)  评论(0编辑  收藏  举报